原理分析
说白了就是解析特定格式的文字,并将处理好的内容回填到需要的表单中。
为了程序的健壮性,我们解析时需要考虑多种情况。
1、文字行数
单行和多行的解析可以分开
单行的情况如下面这种,
姓名: 七七 电话:788 邮箱:qiqi@qiqi.com 地址:啊啊啊
多行的情况可能是
姓名: 七七
电话:788
邮箱:qiqi@qiqi.com
地址:啊啊啊
多行用:const lines = text?.split('\n');
分开解析即可
2、中英文冒号兼容
在填写地址时,用户可能打中文冒号或者英文冒号,我们需要兼容确保识别分割的时候程序不会出问题。
split(/[::]/)
即可
当然,这里也可以写正则去分割空格的情况。
3、移除文本信息前后的无用空格
用trim()
没什么好说的
4、关键信息匹配
我们需要自定义一个关键词汇库去匹配剪贴板文本信息,我们可以考虑所有关键信息放进一个词汇库,也可以根据表单字段数量分开创建多个词汇库。
列如:
1、词汇库放在一起
const keywords = ['姓名','名字','电话','电话号码','号码','手机','手机号','手机号码','邮箱','邮箱地址','邮件','地址','详细地址'
使用这种放一起的关键字的匹配,优势就是词汇库放一起比较灵活,但是后期处理文本信息的时候略微繁琐,需要拿到一段信息后把这段信息移除,否则会干扰下一段信息的获取。
2、多个词汇库
const nameKeywords = ['姓名','名字','联系人']
const phoneKeywords = ['电话','电话号码','号码','手机','手机号','手机号码']
const emailKeywords = [ '邮箱','邮箱地址','邮件']
const addressKeywords = ['地址','详细地址']
缺点是每个关键字词库只能匹配特定的字段,有多少个字段就需要多少个词汇库。
优点,可以精准匹配,大大简化操作。
实践
我们这里用多个词汇库举例,单个词汇库代码太多了,懒得写,下次想起来再更新。
1、获取粘贴板内容
无论你用的那个技术栈,总有获取粘贴板内容的方法,自己用ai搜下就行,用框架的可以搜对应框架的api,原生的就搜js获取。
2、解析
- 定义多个关键字库
const nameKeywords = ['姓名', '名字', '收件人']; // 匹配姓名关键字
const phoneKeywords = ['电话', '手机号码', '手机号', '手机', '联系电话']; // 匹配号码关键字
const provinceKeywords = ['所在地区', '省市区']; // 匹配省市区关键字
const addressKeywords = ['详细地址', '地址', '完整地址']; // 匹配详细地址关键字
- 正则先匹配一遍关键字和值
let name = '';
let phone = '';
let provinceCode: string[] = [];
let address = '';
// 使用正则表达式匹配关键字和值
const regex = new RegExp(
`(${nameKeywords.join('|')})[::](.*?)(${phoneKeywords.join(
'|',
)})[::](.*?)(${provinceKeywords.join('|')})[::](.*?)(${addressKeywords.join(
'|',
)})[::](.*)`,
'i',
);
const match = text.match(regex);
- 区分单行和多行处理方式
if (match) {
// 动态解析关键字和值,处理一行格式的情况
const parsedFields = {
[match[1]]: match[2].trim(),
[match[3]]: match[4].trim(),
[match[5]]: match[6].trim(),
[match[7]]: match[8].trim(),
};
name = nameKeywords.some(keyword => keyword in parsedFields)
? parsedFields[nameKeywords.find(keyword => keyword in parsedFields)!]
: '';
phone = phoneKeywords.some(keyword => keyword in parsedFields)
? parsedFields[phoneKeywords.find(keyword => keyword in parsedFields)!]
: '';
const provinceText = provinceKeywords.some(keyword => keyword in parsedFields)
? parsedFields[provinceKeywords.find(keyword => keyword in parsedFields)!]
: '';
address = addressKeywords.some(keyword => keyword in parsedFields)
? parsedFields[addressKeywords.find(keyword => keyword in parsedFields)!]
: '';
provinceCode = pareProvinceText(provinceText);
}
// 处理多行格式的情况
else {
let provinceText = '';
const lines = text?.split('\n');
lines.forEach(line => {
const trimmedLine = line.trim();
if (nameKeywords.some(keyword => trimmedLine.includes(keyword))) {
name = trimmedLine.split(/[::]/).pop()?.trim() || ''; // 中英文冒号处理
} else if (phoneKeywords.some(keyword => trimmedLine.includes(keyword))) {
phone = trimmedLine.split(/[::]/).pop()?.trim() || '';
} else if (provinceKeywords.some(keyword => trimmedLine.includes(keyword))) {
provinceText = trimmedLine.split(/[::]/).pop()?.trim() || '';
} else if (addressKeywords.some(keyword => trimmedLine.includes(keyword))) {
address = trimmedLine.split(/[::]/).pop()?.trim() || '';
}
});
provinceCode = pareProvinceText(provinceText);
}
-
上面这里pareProvinceText这个函数是我自己的业务函数,处理省市区的,你们不用管)
-
将结果回填
let name = '';
let phone = '';
let provinceCode: string[] = [];
let address = '';
上面的变量是我们保存的结果,回填到需要的地方就行了。
完整示例(用的react-native)
import Clipboard from '@react-native-clipboard/clipboard';
// 解析省市区粘贴板
const pareProvinceText = (provinceText: string) => {
const provinceCode: any[] = [];
let cityList: any[] = []; // 某省下所有市
let districtList: any[] = []; // 某省某区下所有区
let provinceName = '';
areaList?.some((item: any) => {
if (provinceText.includes(item?.label)) {
provinceName = item?.label;
provinceCode.push(item?.value); // 获取匹配到的省code
cityList = item?.children;
}
});
cityList?.some((item: any) => {
if (provinceText?.includes(item?.label)) {
provinceCode.push(item?.value); // 获取匹配到的市code
districtList = item?.children;
}
});
districtList?.some((item: any) => {
if (provinceText?.includes(item?.label)) {
provinceCode.push(item?.value); // 获取匹配到的区code
districtList = item?.children;
}
});
return provinceCode;
};
// 识别剪切板
const onCheckClipboard = () => {
Clipboard.getString()
.then(text => {
console.log('text', text);
if (!text) {
return Toast.text('剪切板无内容');
}
const nameKeywords = ['姓名', '名字', '收件人']; // 匹配姓名关键字
const phoneKeywords = ['电话', '手机号码', '手机号', '手机', '联系电话']; // 匹配号码关键字
const provinceKeywords = ['所在地区', '省市区']; // 匹配省市区关键字
const addressKeywords = ['详细地址', '地址', '完整地址']; // 匹配详细地址关键字
let name = '';
let phone = '';
let provinceCode: string[] = [];
let address = '';
// 使用正则表达式匹配关键字和值
const regex = new RegExp(
`(${nameKeywords.join('|')})[::](.*?)(${phoneKeywords.join(
'|',
)})[::](.*?)(${provinceKeywords.join('|')})[::](.*?)(${addressKeywords.join(
'|',
)})[::](.*)`,
'i',
);
const match = text.match(regex);
if (match) {
// 动态解析关键字和值,处理一行格式的情况
const parsedFields = {
[match[1]]: match[2].trim(),
[match[3]]: match[4].trim(),
[match[5]]: match[6].trim(),
[match[7]]: match[8].trim(),
};
name = nameKeywords.some(keyword => keyword in parsedFields)
? parsedFields[nameKeywords.find(keyword => keyword in parsedFields)!]
: '';
phone = phoneKeywords.some(keyword => keyword in parsedFields)
? parsedFields[phoneKeywords.find(keyword => keyword in parsedFields)!]
: '';
const provinceText = provinceKeywords.some(keyword => keyword in parsedFields)
? parsedFields[provinceKeywords.find(keyword => keyword in parsedFields)!]
: '';
address = addressKeywords.some(keyword => keyword in parsedFields)
? parsedFields[addressKeywords.find(keyword => keyword in parsedFields)!]
: '';
provinceCode = pareProvinceText(provinceText);
}
// 处理多行格式的情况
else {
let provinceText = '';
const lines = text?.split('\n');
lines.forEach(line => {
const trimmedLine = line.trim();
if (nameKeywords.some(keyword => trimmedLine.includes(keyword))) {
name = trimmedLine.split(/[::]/).pop()?.trim() || ''; // 中英文冒号处理
} else if (phoneKeywords.some(keyword => trimmedLine.includes(keyword))) {
phone = trimmedLine.split(/[::]/).pop()?.trim() || '';
} else if (provinceKeywords.some(keyword => trimmedLine.includes(keyword))) {
provinceText = trimmedLine.split(/[::]/).pop()?.trim() || '';
} else if (addressKeywords.some(keyword => trimmedLine.includes(keyword))) {
address = trimmedLine.split(/[::]/).pop()?.trim() || '';
}
});
provinceCode = pareProvinceText(provinceText);
}
// 更新表单数据
formRef.current?.setData({
receiver: name,
phone,
addressCode: provinceCode,
address,
});
})
.catch(error => {
console.log(error);
});
};
参考1、2就行,其他技术栈原理类似。
不懂得留言问。加呐!