JavaScript Regex -查找所有可能的匹配,即使是在已经捕获的匹配中

ve7v8dk2  于 2023-10-22  发布在  Java
关注(0)|答案(3)|浏览(100)

我尝试使用正则表达式和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:A1B2YA1B2Y:A1B3Y一起沿着,即使字符串中的A1B2Y需要是两个匹配的一部分。

u1ehiz5o

u1ehiz5o1#

在不修改正则表达式的情况下,您可以使用.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"]

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

reg.lastIndex = found.index+1;

Demo
最后的结果是一样的。不过,Bergi的更新代码少了一点,执行的faster也稍微少了一点。=]

holgip5t

holgip5t2#

你不能直接从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]);
}

为了不消耗文本,我使用了 zero-width positive look-ahead (?=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,它做了额外的无用的替换工作。

ar7v8xwq

ar7v8xwq3#

不幸的是,它并不像单个string.match那么简单。
原因是您需要重叠匹配,而/g标志给予不了。
你可以使用lookahead:

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

但现在你得到:

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

原因是lookahead是零宽度的,这意味着它只是说明模式是否在您试图匹配的内容之后出现;它不包括在比赛中。
你可以使用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"
];

Here's a fiddle of this in action。打开控制台查看结果
或者,您可以在:上拆分原始字符串,然后循环遍历结果数组,在array[i]array[i+1]都匹配时取出匹配的字符串。

相关问题