在JavaScript中使用全局标志捕获组正则表达式

时间:2015-04-09 23:20:34

标签: javascript regex

我有一个用例,我需要允许通过任意正则表达式处理任意字符串数组,该正则表达式由正则表达式文字或new RegExp()构造函数创建。

一切正常,直到全局g标志与捕获组一起使用。

我在SO上读了几个答案,建议的解决方案是在while循环中使用regex.exec(string),例如 How do you access the matched groups in a JavaScript regular expression?JavaScript regular expressions and sub-matches

我也在IRC上讨论过这个问题,并建议不要一起实施:

  

但除非你这样做,否则你的引擎会出现段错误   使用spidermonkey。

所以这是一个角落的情况,尝试将它粘贴到小提琴或者傻瓜,甚至是控制台,它只是打破了:



var regexString = '([^-]*)';
var flags = 'ig';
var regex = new RegExp(regexString, flags);

var arr = ['some-property-image.png', 'another-prop-video.png', 'y-no-work.bmp'];
var result = [];

arr.forEach(function(item) {
  var match;
  var inter = [];
  while (match = regex.exec(item)) {
    inter.push(match[0]);
  }
});

console.log(result);




我在regex101.com https://regex101.com/r/xG0cL4/1上尝试过 即使我没有量词,即/([^-])/g https://regex101.com/r/yT7sQ2/1

,它也会中断

我的问题:对任意字符串处理任意正则表达式的(correct|safe)方式是什么?

3 个答案:

答案 0 :(得分:1)

它不起作用,因为当' - '到达时,exec()无法匹配' - '字符,但匹配0个字符(因为*),所以它不会跳过它,因此它会被卡住。如果您使用-|([^-]*),则会跳过' - '字符。然后,您需要检查' match.index'财产,看看你是否达到了目的。

此外,如果您的目的是保存匹配的文字,则应添加match[1]而不是match[0]

这有效:

var regexString = '-|([^-]*)'; // or better yet: '([^-]+)' will work also
var flags = 'ig';
var regex = new RegExp(regexString, flags);

var arr = ['some-property-image.png', 'another-prop-video.png', 'y-no-work.bmp'];
var result = [];

arr.forEach(function(item) {
  var match;
  var inter = [];      
  while (match = regex.exec(item)) {
    if (match.index >= item.length) break;
    else if (match[1] !== void 0) inter.push(match[1]);
  }
});

console.log(result);

但为什么不使用' match()'代替?

var regexString = '[^-]+';
var flags = 'gi';
var regex = new RegExp(regexString, flags);

var arr = ['some-property-image.png', 'another-prop-video.png', 'y-no-work.bmp'];
var result = [];

arr.forEach(function(item) {
  var inter = item.match(regex);
});

console.log(result);

答案 1 :(得分:0)

match对象具有index属性,其中包含当前匹配的位置。如果在循环中的两个调用之间保持不变,则意味着您被卡住了。



var regexString = '([^-]*)';
var flags = 'ig';
var regex = new RegExp(regexString, flags);

var arr = ['some-property-image.png', 'another-prop-video.png', 'y-no-work.bmp'];
var result = [];

arr.forEach(function(item) {
  var match;
  var inter = [];
  var lastIndex = -1;
  while (match = regex.exec(item)) {
    if (match.index == lastIndex) {
      break;
    }
    lastIndex = match.index;
    inter.push(match[0]);
  }
  result.push(inter);
});

console.log(result);




答案 2 :(得分:0)

为什么它会崩溃:通过在具有零宽度匹配的循环中使用带有全局标志和exec的RegExp对象来创建无限循环。循环命中第一个' - '但由于否定的字符类而与该字符不匹配。然后它恢复为零长度匹配,因此不会提前exec的索引值。这意味着在下一个循环中,它会在相同的位置重新开始,完成同样的事情......无限。

那就是说,很难说出你究竟想要什么,但为什么不试试match呢?看起来你只关心匹配的字符串,所以exec似乎有点矫枉过正。

如果所需输出是输入数组的一对一结果数组:

function foo(regexp, strings) {
  return strings.reduce(function(matches, str) {
    matches.push(str.match(regexp));
    return matches;
  }, []);
}

foo(/([^-]+)/ig, arr);
// outputs: [["some","property","image.png"],["another","prop","video.png"],["y","no","work.bmp"]]

foo(new RegExp('([^-]+)', 'ig'), arr);
// outputs: [["some","property","image.png"],["another","prop","video.png"],["y","no","work.bmp"]]

即使零宽度匹配,它也不会进入无限循环:

foo(/([^-]*)/ig, arr));
// outputs: [["some","","property","","image.png",""],["another","","prop","","video.png",""],["y","","no","","work.bmp",""]]

如果所需的输出确实是所有匹配的一个数组:

function foo(regexp, strings) {
  return strings.reduce(function(matches, str) {
    return matches.concat(str.match(regexp));
  }, []);
}

foo(/([^-]+)/ig, arr);
// outputs: ["some","property","image.png","another","prop","video.png","y","no","work.bmp"]

foo(new RegExp('([^-]+)', 'ig'), arr);
// outputs:  ["some","property","image.png","another","prop","video.png","y","no","work.bmp"]

foo(/([^-]*)/ig, arr));
// outputs: ["some","","property","","image.png","","another","","prop","","video.png","","y","","no","","work.bmp",""]