let input = `".........这里有50个字符以上。。。。。`
function makeCellFromRowString(row) {
row = row.replace(/,,/g,',-,').replace(/,,/g,',-,').replace(/^,/,'-,').replace(/,$/,',-');
let p = /"([^"]*(?:(?:"")*[^"]*(?:"")*)*)"|([^,]+)/g; // (?:)的意思表示该分组不计入最后匹配结果的分组中
let e = null;
let cells = [];
let temp = null;
while ((e = p.exec(row)) != null) {
temp = (e[2] || e[1]).replace(/""/g,'"');
cells.push(temp);
}
return cells;
}
避免正则中的那些灾难性回溯 Catastrophic backtracking
今天某产品经理突然跑来跟我说线上有了个bug,上传了文件后浏览器卡死奔溃了 内心一惊(这群产品狗是不是又瞎操作),最后经过一番侦察,定位到原来是下面这段代码导致的
当函数的入参是上面input的值的时候,程序就卡住了,这里就发生正则中很容易发生的 回溯灾难
我们现在考虑这样一个正则 /(x+x+)+y/ ,去匹配字符串 'xxxxxxxxxxy'
但是灾难的事情发生了 此时字符串变成了 'xxxxxxxxxx' ,y不见了
点击这里你可以发现10个x一共判断了4085步才判断出正则匹配失败 11个x执行了8180步,12个x执行16371步,步骤几乎是指数式的复杂度 O(2^n),这就是灾难性的回溯
上面这个例子最明智的修改方式无疑是修改成把正则修改成 /xx+y/ 消除嵌套的量词 + 另外一种做法是使用 Possessive Quantifier 就是 /(x+x+)++y/ 简单点说就是让正则引擎更加聪明快速的判断失败
大部分的灾难性回溯造成的原因是 量词 + * 的嵌套使用造成的,所以谨慎使用
最简单避免灾难性回溯的方法就是,当嵌套重复性的操作符时候, 确保对具体的同一段字符串只有一种匹配路径,如果一个内环重复了四次,外环重复了7次匹配的结果和 内环重复6次,外环重复2次的结果一样,正则引擎会尝试回溯他们的组合
回到正题,将代码中的正则简化下就是下面这样,问题就出在嵌套了2层 *
/"[^"]([^"])*"/ 当要匹配的字符串是 "这里有100汉字 的话,由于最后无法匹配到 " , 这里就会有很多的组合了 (99)((1)) (98)((2)) (98)((1)(1)) (97)((1)(1)(1)) (97)((2)(1)) (97)((1)(2)) 。。。。 。。。 。。 。 就会不断的回溯