16

我正在尝试使用带有 javascript 的正则表达式从字符串中获取所有可能的匹配项。看来我这样做的方法与已经匹配的字符串部分不匹配。

变量:

var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y';

var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g;

代码:

var match = string.match(reg);

我得到的所有匹配结果:

A1B1Y:A1B2Y
A1B5Y:A1B6Y
A1B9Y:A1B10Y

我想要的匹配结果:

A1B1Y:A1B2Y
A1B2Y:A1B3Y
A1B5Y:A1B6Y
A1B6Y:A1B7Y
A1B9Y:A1B10Y
A1B10Y:A1B11Y

在我的脑海中,我想A1B1Y:A1B2Y成为一个匹配项A1B2Y:A1B3Y,即使A1B2Y在字符串中需要成为两个匹配项的一部分。

4

3 回答 3

25

.exec在不修改您的正则表达式的情况下,您可以使用和操作正则表达式对象的lastIndex属性将其设置为在每次匹配后的下半场开始匹配时开始匹配。

var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y';
var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g;
var matches = [], found;
while (found = reg.exec(string)) {
    matches.push(found[0]);
    reg.lastIndex -= found[0].split(':')[1].length;
}

console.log(matches);
//["A1B1Y:A1B2Y", "A1B2Y:A1B3Y", "A1B5Y:A1B6Y", "A1B6Y:A1B7Y", "A1B9Y:A1B10Y", "A1B10Y:A1B11Y"]

演示


根据 Bergi 的评论,您还可以获得最后一场比赛的索引并将其递增 1,因此它不会从比赛的后半部分开始匹配,而是从每个比赛的第二个字符开始尝试匹配:

reg.lastIndex = found.index+1;

演示

最后的结果是一样的。不过,Bergi 的更新代码少了一点,执行速度也快了一点。=]

于 2013-02-13T21:14:33.570 回答
4

您无法从中获得直接结果match,但可以通过RegExp.exec对正则表达式进行一些修改来生成结果:

var regex = /A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g;
var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'
var arr;
var results = [];

while ((arr = regex.exec(input)) !== null) {
    results.push(arr[0] + arr[1]);
}

为了不消耗文本,我使用了零宽度正向(?=pattern)预测,以便可以重新匹配重叠部分。

实际上,可以滥用replace方法来达到相同的结果:

var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'
var results = [];

input.replace(/A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g, function ($0, $1) {
    results.push($0 + $1);
    return '';
});

但是,由于它是replace,它会进行额外的无用替换工作。

于 2013-02-13T21:15:32.557 回答
3

不幸的是,它并不像单个string.match.

原因是你想要重叠的匹配,而/g标志没有给你。

您可以使用前瞻:

var re = /A\d+B\d+Y(?=:A\d+B\d+Y)/g;

但现在你得到:

string.match(re); // ["A1B1Y", "A1B2Y", "A1B5Y", "A1B6Y", "A1B9Y", "A1B10Y"]

原因是前瞻是零宽度,这意味着它只是说明模式是否出现在您尝试匹配的内容之后;它不包括在比赛中。

你可以exec用来尝试抓住你想要的东西。如果正则表达式有/g标志,您可以exec重复运行以获取所有匹配项:

// using re from above to get the overlapping matches

var m;
var matches = [];
var re2 = /A\d+B\d+Y:A\d+B\d+Y/g; // make another regex to get what we need

while ((m = re.exec(string)) !== null) {
  // m is a match object, which has the index of the current match
  matches.push(string.substring(m.index).match(re2)[0]);
}

matches == [
  "A1B1Y:A1B2Y", 
  "A1B2Y:A1B3Y", 
  "A1B5Y:A1B6Y", 
  "A1B6Y:A1B7Y", 
  "A1B9Y:A1B10Y", 
  "A1B10Y:A1B11Y"
];

这是一个在行动中的小提琴。打开控制台查看结果

或者,您可以在 上拆分原始字符串:,然后循环遍历结果数组,取出匹配时匹配的那些,array[i]并且array[i+1]两者都匹配您想要的。

于 2013-02-13T21:28:19.433 回答