正则表达式。如何从此字符串中获取多个匹配项?

Regex. How to get multiple matches from this string?

我正在使用 javascript 正则表达式。 假设我有以下字符串:

XXX_1_XXX XXX_2_XXX XXX_3_XXX YYY_1_YYY YYY_2_YYY YYY_3_YYY

并且我想 运行 一个正则表达式并使用此模式获得结果:

Match1
1.    XXX_1_XXX
2.    YYY_1_YYY
Match2
1.    XXX_2_XXX
2.    YYY_2_YYY
Match3
1.    XXX_3_XXX
2.    YYY_3_YYY

我试过这个的变体:

/(XXX_(.)_XXX)(.)*?(YYY__YYY)/g

但它仅在第一场比赛时停止。

有什么方法可以用正则表达式做到这一点吗?或者我最好将它作为一个数组进行迭代?

匹配在字符串上迭代,正则表达式仅在上一个匹配结束后搜索更多匹配。这保证了进度,因为空字符串会导致无限循环。

但是你可以通过以下方式解决这个问题:

var text = "XXX_1_XXX XXX_2_XXX XXX_3_XXX YYY_1_YYY YYY_2_YYY YYY_3_YYY";
var re = /(XXX_(.)_XXX)(.)*?(YYY__YYY)/;
while((m = re.exec(text)) !== null) {
    alert(JSON.stringify(m));//the result (print)
    //do something with m
    text = text.substring(m.index+1); //this is not the same as /g
    // "/g" would be text = text.substring(m.index+m[0].length+1);
}

该程序的工作方式如下:您不使用 /g 修饰符,因此只完成一次匹配。

  1. 每次迭代,您尝试将字符串与正则表达式匹配
  2. 如果它匹配,您确定 .index 匹配开始的位置并将字符串(包括)删除到该点
  3. 您使用修改后的字符串重复搜索,直到该字符串也找不到收敛。

JSFiddle.

Note: there is one case where this might fail: if the empty string can be matched as well, since at the end of the string, it will keep matching the empty string and cutting will result in another empty string. It's however easy to implement a zero-length-check. This issue does not occur with .


Note: another aspect that one must take into account is that this doesn't require "global" progression. The string XXX_1_XXX XXX_2_XXX XXX_3_XXX YYY_1_YYY YYY_3_YYY YYY_2_YYY (mind the swapped values in the YYY_|_YYYY part), will give the same result.

网站 regex101.com 是找出正确正则表达式的重要资源。我准备了两个例子:

/([XY]{3}_[0-3]_[XY]{3})/g

将return:

MATCH 1
1. [0-9] XXX_1_XXX
MATCH 2
1. [10-19] XXX_2_XXX
MATCH 3
1. [20-29] XXX_3_XXX
MATCH 4
1. [30-39] YYY_1_YYY
MATCH 5
1. [40-49] YYY_2_YYY
MATCH 6
1. [50-59] YYY_3_YYY

https://regex101.com/r/xS9eA5/1

/(?:([XY]{3}_[0-3]_[XY]{3}) ([XY]{3}_[0-3]_[XY]{3}))/g

将return:

MATCH 1
1. [0-9] XXX_1_XXX
2. [10-19] XXX_2_XXX
MATCH 2
1. [20-29] XXX_3_XXX
2. [30-39] YYY_1_YYY
MATCH 3
1. [40-49] YYY_2_YYY
2. [50-59] YYY_3_YYY

https://regex101.com/r/xS9eA5/2

问题是在第一次匹配后,正则表达式引擎的内部索引设置在 "YYY_*_YYY" 之后。

幸运的是,在循环中您可以将该位置移动到 "XXX_*_XXX" 匹配之后的右侧:

var s = 'XXX_1_XXX XXX_2_XXX XXX_3_XXX YYY_1_YYY YYY_2_YYY YYY_3_YYY';
var re = /(XXX_(\d)_XXX).*?(YYY__YYY)/g;

while ((match = re.exec(s)) !== null) {
  console.log(match[1], match[3]);
  // move to start of last match plus length of first submatch
  re.lastIndex = match.index + match[1].length;
}

输出

"XXX_1_XXX"
"YYY_1_YYY"

"XXX_2_XXX"
"YYY_2_YYY"

"XXX_3_XXX"
"YYY_3_YYY"