JavaScript - 正则表达式访问多个匹配项

26

我有这段文字

txt = "Local residents o1__have called g__in o22__with reports...";
在这个任务中,我需要获取在每个 o__ 之间的数字列表。

如果我执行以下操作:

txt.match(/o([0-9]+)__/g);
我会得到。
["o1__", "o22__"]

但是我想要

["1", "22"]

我该怎么做?

3个回答

32

请参考这个问题

txt = "Local residents o1__have called g__in o22__with reports...";
var regex = /o([0-9]+)__/g
var matches = [];
var match = regex.exec(txt);
while (match != null) {
    matches.push(match[1]);
    match = regex.exec(txt);
}
alert(matches);

1
我不知道该选择哪一个,你的是第一个,但@friend00更详细 :) - Pierre de LESPINAY
3
好的,让我们验证你的身份,你需要比@jfriend00拥有更高的声望值 :) - Pierre de LESPINAY
11
导致了一个无限循环。 - Rudi Strydom

18
你需要在正则表达式对象上使用.exec(),并带有g标志重复调用它,以便像这样获取连续的匹配:
var txt = "Local residents o1__have called g__in o22__with reports...";
var re = /o([0-9]+)__/g;
var matches;
while ((matches = re.exec(txt)) != null) {
    alert(matches[1]);
}

在正则表达式对象中,前一个匹配的状态被存储为lastIndex属性,下一次匹配会从该属性指定的位置开始。

你可以点击这里查看演示:http://jsfiddle.net/jfriend00/UtF6J/

使用这种方式的正则表达式在这里进行了描述:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/RegExp/exec


我不知道该选择哪一个,你的更详细,但@Soldier.moth的是第一个 :) - Pierre de LESPINAY
也许有几个错别字,但是 Soldier 的代码不起作用,因为它只调用了一次 regex.exec()(它必须作为循环的一部分被多次调用),如果匹配到任何内容,它将进入无限循环,因为一旦 while 循环开始,match 的值就不会改变。 - jfriend00
糟糕!明显是打错了,已修复。 - Bobby
如果我调用验证此代码 re.test(txt) 然后尝试使用 do while,它将从第二个匹配开始,我们将失去第一个匹配。 - fdrv
@Jek-fdrv - 是的,如果你在正则表达式中使用了 g 选项,那么每次调用 .test().exec() 方法时都会将匹配位置向下移动一位。这个状态存储在正则表达式对象本身中。如果需要,你可以通过将正则表达式的 .lastIndex 属性设置为 0 来重置该状态。 - jfriend00

4
/o([0-9]+?)__/g

这应该是可以正常工作的。点击这里并搜索“惰性星号”即可。
var rx = new RegExp( /o([0-9]+?)__/g );
var txt = "Local residents o1__have called g__in o22__with reports...";
var mtc = [];
while( (match = rx.exec( txt )) != null ) {
        alert( match[1] );
        mtc.push(match[1]);
}

Jek-fdrv在评论中指出,如果在while循环之前调用rx.test,则会跳过一些结果。这是因为RegExp对象包含一个lastIndex字段,它跟踪字符串中最后一个匹配的索引。当lastIndex更改时,RegExp将从其lastIndex值开始匹配,因此字符串的一部分将被跳过。以下是一个小例子:

var rx = new RegExp( /o([0-9]+?)__/g );
var txt = "Local residents o1__have called g__in o22__with reports...";
var mtc = [];
console.log(rx.test(txt), rx.lastIndex); //outputs "true 20"
console.log(rx.test(txt), rx.lastIndex); //outputs "true 43"
console.log(rx.test(txt), rx.lastIndex); //outputs "false 0" !!!
rx.lastIndex = 0; //manually reset lastIndex field works in Chrome
//now everything works fine
while( (match = rx.exec( txt )) != null ) {
        console.log( match[1] );
        mtc.push(match[1]);
}

给我相同的结果。JavaScript 中实现了懒加载吗? - Pierre de LESPINAY
是的,它们是。我进行了编辑并添加了一些代码,本地测试通过。会弹出两个警报框,分别显示数字"1"和"22"。 - CaNNaDaRk
现在它也填充了mtc数组。 - CaNNaDaRk
如果我调用验证此代码 rx.test(txt),然后尝试使用do while,它将从第二个匹配开始,并且我们会失去第一个匹配。 - fdrv
没错,每次调用test方法时,RegExp对象的lastIndex成员都会增加到下一个匹配位置,如果您不重置它(通过将其设置为0),下一次调用match或test时,字符串仅从lastIndex值进行分析。尝试在调用test后立即设置“rx.lastIndex = 0;”,然后再次调用match。这适用于Chrome。我将编辑答案并添加一个小例子。 - CaNNaDaRk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接