Files
jurong_circle_front_app/uni_modules/vk-uview-ui/components/u-picker/address-discern.js
2025-09-12 17:23:03 +08:00

308 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class AddressDiscern {
// 初始化数据源
constructor(dataSource = {}) {
this.dataSource = dataSource;
}
// 智能解析收货地址
discern(text) {
if (!text) return { code: -1, msg: "地址文本不能为空" };
// 清理文本,去除多余空格
text = text.trim();
// 先解析地址,因为地址最容易识别
const positionRes = this.regionDiscern(text);
if (positionRes.code !== 0) return positionRes;
// 再解析姓名和手机号
const { name, mobile } = this.nameMobileDiscern(positionRes.not_address_text);
const status = name && mobile && positionRes.data ? 1 : 0;
let msg = "ok";
if (status === 0) {
msg = "未识别:";
if (!name) msg += "姓名、";
if (!mobile) msg += "手机号、";
msg = msg.slice(0, -1);
}
const res = {
code: 0,
msg,
status, // 1 表示全部识别成功0 表示部分成功
data: {
name, // 姓名
mobile, // 手机号
position: positionRes.data, // 省市区街道信息
}
};
return res;
}
// 智能识别省市区
regionDiscern(addressText) {
const { provinces, citys, areas } = this.dataSource;
const province = {};
const city = {};
const area = {};
let address = "";
if (!addressText) return { code: -1, msg: "地址文本不能为空" };
addressText = addressText.trim();
// 获取省份索引
const findProvinceIndex = () => {
const index = provinces.findIndex(({ name }) => addressText.includes(name.substring(0, 2)));
return index;
};
// 获取地级市索引
const findCityIndex = (citys) => {
const index = citys.findIndex(({ name }) => addressText.includes(name.slice(0, -1)));
return index;
};
// 获取县级市索引
const findAreaIndex = (areas) => {
const index = areas.findIndex(({ name }) => {
const reg = name.length > 2 ? `${name}|${name.slice(0, -1)}` : name;
const areaRegExp = new RegExp(reg);
if (areaRegExp.test(addressText)) {
address = addressText.replace(areaRegExp, "{{~}}").split("{{~}}")[1] || "";
address = address.split(new RegExp("[^\\u4e00-\\u9fa5a-zA-Z0-9+-()]+", "g"))[0];
return true;
}
return false;
});
return index;
};
// 通过市倒推省份
const findProvinceByCity = () => {
for (let i = 0; i < citys.length; i++) {
const index = findCityIndex(citys[i]);
if (index !== -1) {
return { provinceIndex: i, cityIndex: index };
}
}
return { provinceIndex: -1, cityIndex: -1 };
};
// 通过区倒推市和省份
const findProvinceByArea = () => {
for (let i = 0; i < areas.length; i++) {
for (let j = 0; j < areas[i].length; j++) {
const index = findAreaIndex(areas[i][j]);
if (index !== -1) {
return { provinceIndex: i, cityIndex: j, areaIndex: index };
}
}
}
return { provinceIndex: -1, cityIndex: -1, areaIndex: -1 };
};
// 省
let provinceIndex = findProvinceIndex();
let cityIndex = -1;
let areaIndex = -1;
if (provinceIndex === -1) {
// 如果省份没有找到,通过市倒推省份
const cityResult = findProvinceByCity();
provinceIndex = cityResult.provinceIndex;
cityIndex = cityResult.cityIndex;
}
if (provinceIndex === -1) {
// 如果市没有找到,通过区倒推市和省份
const areaResult = findProvinceByArea();
provinceIndex = areaResult.provinceIndex;
cityIndex = areaResult.cityIndex;
areaIndex = areaResult.areaIndex;
}
if (provinceIndex === -1) return { code: -1, msg: "省份没有找到,请输入正确的地址" };
Object.assign(province, provinces[provinceIndex]);
const cityList = citys[provinceIndex];
// 市
if (cityIndex === -1) {
cityIndex = findCityIndex(cityList);
if (cityIndex === -1) return { code: -1, msg: "地级市没有找到,请输入正确的地址" };
}
Object.assign(city, cityList[cityIndex]);
// 区
const areaList = areas[provinceIndex][cityIndex];
if (areaIndex === -1) {
areaIndex = findAreaIndex(areaList);
if (areaIndex === -1) return { code: -1, msg: "县级市没有找到,请输入正确的地址" };
}
Object.assign(area, areaList[areaIndex]);
const formatted_address = `${province.name}${city.name}${area.name}${address}`;
const provinceName = province.name.substring(0, 2); // 省份名称前两个字
const not_address_text = (addressText.substring(0, addressText.indexOf(provinceName)) + addressText.substring(addressText.indexOf(address) + address.length)).trim();
return {
code: 0,
msg: "ok",
data: {
province,
city,
area,
address,
formatted_address
},
not_address_text
};
}
// 智能解析姓名和手机号
nameMobileDiscern(text) {
if (!text) return { name: "", mobile: "" };
let name = "";
let mobile = "";
// 手机号正则匹配(支持多种格式)
const mobilePatterns = [
new RegExp('1\\d{2}([\\s-]?\\d{4}){2}', 'g')
];
let mobileMatchText;
// 查找手机号
for (const pattern of mobilePatterns) {
const matches = text.match(pattern);
if (matches && matches.length > 0) {
// 取第一个匹配的手机号,去除格式符号
mobile = matches[0].replace(new RegExp("[\\s\\-\\.]", "g"), "");
mobileMatchText = matches[0];
break;
}
}
// 从文本中移除手机号,便于后续识别姓名
let cleanText = text;
if (mobile) {
cleanText = cleanText.replace(mobileMatchText, "");
}
// 处理常见的标签前缀(扩展更多模式)
const labelPatterns = [
new RegExp("^姓名[:]\\s*"),
new RegExp("^收货人[:]\\s*"),
new RegExp("^收件人[:]\\s*"),
new RegExp("^联系人[:]\\s*"),
new RegExp("^name[:]\\s*", "i"),
new RegExp("^收[:]\\s*"),
new RegExp("^人[:]\\s*"),
new RegExp("^电话[:]\\s*"),
new RegExp("^手机[:]\\s*"),
new RegExp("^tel[:]\\s*", "i"),
new RegExp("^phone[:]\\s*", "i"),
new RegExp("^mobile[:]\\s*", "i"),
new RegExp("^地址[:]\\s*"),
new RegExp("^address[:]\\s*", "i"),
new RegExp("^收货地址[:]\\s*"),
new RegExp("^收件地址[:]\\s*"),
];
// 移除标签前缀
for (const pattern of labelPatterns) {
cleanText = cleanText.replace(pattern, "");
}
// 清理多余的空格和标点
cleanText = cleanText.replace(new RegExp("\\s+", "g"), " ").trim();
// 姓名识别规则(按优先级排序,更具体的模式在前)
const namePatterns = [
// 英文+称谓vk先生、John先生、Mary女士等- 最具体,优先匹配
new RegExp("[A-Za-z]+[\\u4e00-\\u9fa5]{1,3}", "g"),
// 中文姓名2-6个汉字支持复姓和少数民族姓名
new RegExp("[\\u4e00-\\u9fa5]{2,6}", "g"),
// 英文姓名(支持多种格式:全名、简称、首字母等)
new RegExp("[A-Za-z]+(\\s+[A-Za-z]+)*", "g"),
];
// 查找姓名
for (const pattern of namePatterns) {
const matches = cleanText.match(pattern);
if (matches && matches.length > 0) {
// 过滤掉一些明显不是姓名的词
const validNames = matches.filter(match => {
// 过滤掉常见的地址词汇
const addressWords = ['省', '市', '区', '县', '镇', '村', '路', '街', '号', '楼', '室', '单元', '栋', '层', '小区', '大厦', '广场', '花园'];
const isAddressWord = addressWords.some(word => match.includes(word));
// 过滤掉常见的标签词汇
const labelWords = ['姓名', '收货人', '收件人', '联系人', '收', '人', '电话', '手机', '地址', '收货', '收件', '联系'];
const isLabelWord = labelWords.some(word => match.includes(word));
// 过滤掉纯数字
const isNumber = new RegExp("^\\d+$").test(match);
// 过滤掉太短的词但允许英文简称如vk、ab等
const isTooShort = match.length < 2;
// 过滤掉太长的词中文超过8个字英文超过25个字符可能是地址或其他信息
// 增加长度限制以支持"英文+称谓"的格式
const isChinese = new RegExp("[\\u4e00-\\u9fa5]").test(match);
const isEnglishWithTitle = new RegExp("^[A-Za-z]+[\\u4e00-\\u9fa5]{1,3}$").test(match);
const isTooLong = isEnglishWithTitle ? false : (isChinese ? match.length > 8 : match.length > 25);
// 过滤掉包含特殊字符的词(但允许英文中的空格和中文)
const hasSpecialChars = isChinese ?
new RegExp("[^\\u4e00-\\u9fa5a-zA-Z\\s]").test(match) :
new RegExp("[^a-zA-Z\\s]").test(match);
return !isAddressWord && !isLabelWord && !isNumber && !isTooShort && !isTooLong && !hasSpecialChars;
});
if (validNames.length > 0) {
// 优先选择较短的姓名(通常姓名不会太长)
name = validNames.sort((a, b) => a.length - b.length)[0];
break;
}
}
}
// 如果没有通过正则找到姓名,尝试其他方法
if (!name) {
// 尝试从剩余文本中提取可能的姓名
const remainingText = cleanText.trim();
if (remainingText) {
// 按空格或标点符号分割
const parts = remainingText.split(new RegExp("[\\s,。.!?;:]"));
for (const part of parts) {
const trimmedPart = part.trim();
// 检查是否是中文姓名2-6个汉字、英文姓名2-20个字母或英文+称谓
const isChineseName = new RegExp("^[\\u4e00-\\u9fa5]{2,6}$").test(trimmedPart);
const isEnglishName = new RegExp("^[a-zA-Z]{2,20}$").test(trimmedPart);
const isEnglishWithTitle = new RegExp("^[a-zA-Z]+[\\u4e00-\\u9fa5]{1,3}$").test(trimmedPart);
if (isChineseName || isEnglishName || isEnglishWithTitle) {
// 再次过滤地址词汇和标签词汇
const addressWords = ['省', '市', '区', '县', '镇', '村', '路', '街', '号', '楼', '室', '单元', '栋', '层', '小区', '大厦', '广场', '花园'];
const labelWords = ['姓名', '收货人', '收件人', '联系人', '收', '人', '电话', '手机', '地址', '收货', '收件', '联系'];
const isAddressWord = addressWords.some(word => trimmedPart.includes(word));
const isLabelWord = labelWords.some(word => trimmedPart.includes(word));
if (!isAddressWord && !isLabelWord) {
name = trimmedPart;
break;
}
}
}
}
}
// 最终清理:去除姓名中的多余空格
if (name) {
name = name.replace(new RegExp("\\s+", "g"), "").trim();
}
return { name, mobile };
}
}
export default AddressDiscern;