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

Regex. How to get multiple matches from this string?

本文关键字:获取 字符串 正则表达式      更新时间:2023-09-26

我正在使用javascript regex。假设我有以下字符串:

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_'2_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_'2_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.

注意:有一种情况可能会失败:如果空字符串也可以匹配,因为在字符串的末尾,它将继续匹配空字符串,并且剪切将导致另一个空字符串。但是,实现零长度检查很容易。@Ja的答案不会出现此问题。


注意:必须考虑的另一个方面是,这不需要"全局"进展。字符串XXX_1_XXX XXX_2_XXX XXX_3_XXX YYY_1_YYY YYY_3_YYY YYY_2_YYY(请注意YYY_|_YYYY部分中交换的值)将给出相同的结果。

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

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

将返回:

匹配 1
1. [0-9] XXX_1_XXX
匹配 2
1. [10-19] XXX_2_XXX
匹配 3
1. [20-29] XXX_3_XXX
匹配 4
1. [30-39] YYY_1_YYY
匹配 5
1. [40-49] YYY_2_YYY
匹配 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

将返回:

匹配 1
1. [0-9] XXX_1_XXX
2. [10-19] XXX_2_XXX
匹配 2
1. [20-29] XXX_3_XXX
2. [30-39] YYY_1_YYY
匹配 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_'2_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"