最近有一个客户需要批量录入数据,但是给的是word文档的格式,非结构化数据,需要自行解析成结构数据录入;
程序读取后格式基本如下:
25.《Book Name》(XXX) KJDKLJLKJSLKJLKJ数控刀具付款啦收到束带结发建设大街打卡机的( )。
A.都是发生的 B.阿斯蒂芬
C.阿斯顿发的 D.阿第三方
26.啊收到发斯蒂芬时代峰峻上岛咖啡( )
A.阿萨德 B.阿斯蒂芬是的
C.阿斯蒂芬莱克斯顿就发到 D.打发地方
27.阿斯顿发大水( )
A.阿萨德 B.阿斯蒂芬是的
C.阿斯蒂芬莱克斯顿就发到 D.打发地方
需要抽取题目,可选项;
首先分割出题,也就是数字.到数字.为一道;
先写正则如下:/(\d{1,2})\.(.*)(\d{1,2})\./g
const str = `...`;
const reg = /(\d{1,2})\.(.*)(\d{1,2})\./g;
console.log(str.match(reg));
此时输出为null;
因为.*不匹配换行
, 正则需要改动为如下/(\d{1,2})\.((.|\n)*)(\d{1,2})\./g
, 或者将字符串预处理,去掉换行;
此时输出发现从25匹配到了27,发现多匹配了,此时就需要使用正则的非贪婪模式
, 使用?来转换贪婪模式(尽可能多的匹配字符)和非贪婪模式(尽可能少的匹配字符),此时正则:/(\d{1,2})\.((.|\n)?*)(\d{1,2})\./g
;
此时输出结尾发现多了26., 导致后面无法继续匹配,这就需要另一个正则语法:前瞻断言
:(?=pattern), 在 JavaScript 的正则表达式中,(?=pattern)
是一个前瞻断言,它会匹配那些后面跟着与 pattern
匹配的字符串的位置。这个匹配不消耗字符,也就是说,匹配结果不包含 pattern
,并且下一次匹配还会从这个位置开始。
最终修改正则如下:/(\d{1,2})\.((.|\n)*?)(?=(\d{1,2}\.))/g
;
切割代码:
const reg = /(\d{1,2})\.((.|\n)*?)(?=(\d{1,2}\.))/g;
let lastIndex = undefined,
curMatch = null;
const collect = [];
while ((curMatch = reg.exec(str, ""))) {
lastIndex = curMatch.index + curMatch[0].length;
collect.push(curMatch[0]);
}
if (lastIndex) {
collect.push(str.slice(lastIndex));
}
const result = collect.reduce((acc, item) => {
const split = item.split(/[A-D]/);
return {
...acc,
title: split.shift(),
options: split,
}
}, {});