最近有一个需求,是要在前端做一个地址识别功能。。。确认不交给后台调接口去用ai识别吗?
看需求图:(识别出来的地址要给勾选上,这是个四级联动)
说一下解决方案:先将输入的地址格式化,去掉空格,统一把中文标点转换成英文,去掉换行符等。。。然后对字符串进行切割,进行强匹配,输出匹配上的数组。
地址识别组件:
import React, { FC, useState } from "react"; import { FormShape, createForm } from "@components/Form"; import { Textarea } from "@components/Input"; import Tooltip from "@components/Tooltip"; import { errorTip, successTip } from "@components/Tips"; type DistinguishProps = { form: FormShape; addressCheck?: (...args) => void; addressData: any; }; const Distinguish: FC<DistinguishProps> = ({ form, addressCheck, addressData }) => { const [successAdd, setSuccessAdd] = useState([]); const [isSuccess, setIsSuccess] = useState(""); const re1 = /[;]/; const re2 = /[:]/; // 处理识别数据 const dealText = value => { if (!value) return; // 格式化,转换成英文字符,方便切割 let str = value .replace(/:/g, ":") .replace(/;/g, ";") .replace(/[\r\n]/g, "") .replace(/\t/g, " "); let newData1 = []; let newData2 = []; let newData3 = []; try { if (re1.test(str)) { newData1 = str.split(";"); newData1.forEach(item1 => { item1 ? newData2.push(item1) : " "; }); newData2.forEach(item2 => { if (re2.test(item2)) { newData3.push({ [item2.split(":")[0]]: item2.split(":")[1].split(" "), }); } else { newData3.push({ [item2]: [] }); } }); } else { if (re2.test(str)) { newData1 = str.split(":"); newData1.forEach(item1 => { item1 ? newData2.push(item1) : " "; }); newData3.push({ [newData2[0]]: newData2[1].split(" "), }); } else { newData3.push({ [str]: [] }); } } return newData3; } catch (e) { errorTip("地址识别失败!请按照提示的格式输入地址信息。"); setSuccessAdd([]); } }; // 数组对象去重,合并 const mergeData = value => { let initArr = []; let initData = {}; let data = xt.cloneDeep(value); //深拷贝 if (data.length > 0) { data.forEach(item => { if (typeof item == "string") { initArr.push(item); } else { let map = item; for (let k in map) { if (k != null && k != "null") { if (initData.hasOwnProperty(k)) { initData[k] += "," + map[k]; } else { initData[k] = map[k]; } } } } }); } Object.keys(initData).forEach(key => { if (initData[key]) { let a = Array.from(new Set(initData[key].split(","))).join(","); initArr.push({ [key]: a }); } else { initArr.push(key); } }); return initArr; }; // 地址匹配 const addressPick = (val: any) => { let errAddress = []; // 识别失败地址 let sucessAddress = []; // 识别成功地址 let inputAddress = val; // 输入的地址 let propsData = xt.cloneDeep(addressData); // 识别选中的地址 try { inputAddress.forEach(item => { // @ts-ignore if (Object.values(item)?.flat().length) { // 选中区下面的街道 Object.values(item) // @ts-ignore .flat() .forEach(address => { propsData.forEach(data => { // @ts-ignore if (data.nameCN == xt.nesGame(Object.keys(item)?.flat()[0])) { data?.childrenStreet.forEach(a => { if (a.nameCN == xt.nesGame(address)) { // xt.nesGame去掉空格 sucessAddress.push({ [data.nameCN]: address }); a.choose = true; } }); } }); }); } else { // 直接选中区以及下面所有的街道 propsData.forEach(data => { // @ts-ignore if (data.nameCN == xt.nesGame(Object.keys(item)?.flat()[0])) { data.choose = true; data?.childrenStreet.forEach(a => { a.choose = true; }); // @ts-ignore sucessAddress.push(xt.nesGame(Object.keys(item)?.flat()[0])); } }); } }); if (sucessAddress.length > 0) { setIsSuccess("识别成功地址"); successTip("识别成功"); addressCheck(Array.from(new Set(sucessAddress))); setSuccessAdd(mergeData(sucessAddress)); // 识别成功地址 } else { setIsSuccess("地址识别失败!请检查后再试"); setSuccessAdd([]); } } catch (e) { errorTip("地址匹配失败!请检查后再试"); setSuccessAdd([]); } }; // 提交给父组件 // 宝安区:福永街道 石岩街道 航城街道 福海街道 西乡街道 西乡街道;罗湖区 const submit = () => { setIsSuccess(""); form.validateFields((error, value: any) => { if (error) return; addressPick(dealText(value.note)); }); }; const cancel = () => { form.resetFields(); setSuccessAdd([]); setIsSuccess(""); }; return ( <div className="pb-20" style={{ border: "1px solid #eaedf3", borderRadius: "4px", backgroundColor: "#fff" }} > <Textarea form={form} fieldName="note" textareaStyle={{ border: "none" }} placeholder={ "请粘贴文本至此处,自动识别区、县、街道名称并选中,若有多个街道请以区名或县名加冒号开头,多个街道以空格隔开,以分号结束,若需选中整个区或县所有街道则直接输入区名或县名以分号结束。\n例:坪山区:坪山街道 坑梓街道;南山区;" } style={{ width: "100%", border: "none" }} maxLength={300} showError="down" rules={false} normalize={(val, prev) => { if (val.length > 300) return prev.trim(); if (!val.trim().length || val.length === 300) return val.trim(); return val; }} /> <div className="mt-20 pr-20 flex-align-center" style={{ paddingLeft: "15px" }}> <button className="button-primary mr-20" onClick={submit}> 识别文本 </button> <button className="button-default" onClick={cancel}> 清空 </button> <div className="ml-30"> <span className="mr-5 font12 c-606266" style={{ color: isSuccess == "识别成功地址" ? "" : "#FF6666" }} > {isSuccess} </span> {!!successAdd.length && ( <Tooltip overlay={ <> {successAdd.map((val, index) => { if (typeof val === "string") { return <p>{val};</p>; } else { return ( <p> {Object.keys(val)[0]}: {Array.from(new Set(Object.values(val))).join( "," )} </p> ); } })} </> } > <i className={"wsf-icon-question"} /> </Tooltip> )} </div> </div> </div> ); }; export default createForm()(Distinguish);
标签:val,前端,地址,let,forEach,push,识别,data From: https://www.cnblogs.com/tristers/p/16736997.html