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

时间:2015-01-11 10:35:21

标签: javascript regex

我正在使用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_\2_YYY)/g

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

有没有办法用正则表达式做到这一点?或者我最好将其作为一个数组进行迭代?

3 个答案:

答案 0 :(得分:1)

匹配是对字符串的迭代,只有正则表达式的搜索者在上一次匹配结束后之后更多匹配。这可以保证进度,因为空字符串可能导致无限循环。

但您可以按如下方式解决此问题:

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. 您使用修改后的字符串重复搜索,直到该字符串也找不到收敛状态。
  4. JSFiddle

      

    注意:有一种情况可能会失败:如果空字符串也可以匹配,因为在字符串的末尾,它将保持匹配空字符串并且将导致切割在另一个空字符串中。然而,实现零长度检查很容易。 @Ja͢ck's answer无法解决此问题。


      

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

答案 1 :(得分:1)

网站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

答案 2 :(得分:1)

问题是在第一次匹配之后,正则表达式引擎的内部索引设置在“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"