从一段字符处理学习正则

24 阅读2分钟

最近有一个客户需要批量录入数据,但是给的是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,
    }
}, {});