如何将重叠字符串与正则表达式匹配?

时间:2013-12-30 04:19:08

标签: javascript regex

假设我有字符串

"12345"

如果我.match(/\d{3}/g),我只能获得一场比赛"123"。为什么我没有[ "123", "234", "345" ]

6 个答案:

答案 0 :(得分:15)

单独使用正则表达式无法做到这一点,但你可以非常接近:

var pat = /(?=(\d{3}))\d/g;
var results = [];
var match;

while ( (match = pat.exec( '1234567' ) ) != null ) { 
  results.push( match[1] );
}

console.log(results);

换句话说,你捕捉前瞻中的所有三个数字,然后返回并以正常方式匹配一个字符,以提前匹配位置。你如何消费这个角色并不重要; .同样适用\d。如果你真的喜欢冒险,你可以只使用前瞻,让JavaScript处理颠簸。

此代码改编自this answer。我会将这个问题标记为该问题的副本,但OP接受了另一个较小的答案。

答案 1 :(得分:13)

带有全局标志正则表达式的string#match返回匹配的子字符串的数组。 /\d{3}/g正则表达式匹配且 使用 (= 读入缓冲区并将其索引前进到当前匹配字符后的位置 )3位数序列。因此,在"吃饭后#34; 123,索引位于3之后,唯一剩下的用于解析的子字符串是45 - 此处不匹配。

我认为regex101.com 使用的技术在这里也值得考虑:使用零宽度断言(带捕获组的正向前瞻)来测试输入字符串中的所有位置。每次测试后, RegExp.lastIndex (它是正则表达式的读/写整数属性,指定开始下一个匹配的索引)是高级"手动& #34;避免无限循环。

请注意,这是一种在.NET(Regex.Matches),Python(re.findall),PHP(preg_match_all),Ruby(String#scan)中实现的技术,可以使用在Java中也是如此。

这是一个演示:



var re = /(?=(\d{3}))/g;
var str = '12345';
var m, res = [];
 
while (m = re.exec(str)) {
    if (m.index === re.lastIndex) {
        re.lastIndex++;
    }
    res.push(m[1]);
}

console.log(res);




这是regex101.com demo

请注意,同样可以使用" regular"消费\d{3}模式并在每次成功匹配后手动将re.lastIndex设置为m.index+1值:



var re = /\d{3}/g;
var str = '12345';
var m, res = [];

while (m = re.exec(str)) {
    res.push(m[0]);
    re.lastIndex = m.index + 1; // <- Important
}
console.log(res);
&#13;
&#13;
&#13;

答案 2 :(得分:10)

当表达式匹配时,通常消耗匹配的字符。因此,在表达式匹配123后,只剩下45,这与模式不匹配。

答案 3 :(得分:3)

要回答“如何”,您可以手动更改上次匹配的索引(需要循环):

var input = '12345', 
    re = /\d{3}/g, 
    r = [], 
    m;
while (m = re.exec(input)) {
    re.lastIndex -= m[0].length - 1;
    r.push(m[0]);
}
r; // ["123", "234", "345"]

这是一个方便的功能:

function matchOverlap(input, re) {
    var r = [], m;
    // prevent infinite loops
    if (!re.global) re = new RegExp(
        re.source, (re+'').split('/').pop() + 'g'
    );
    while (m = re.exec(input)) {
        re.lastIndex -= m[0].length - 1;
        r.push(m[0]);
    }
    return r;
}

用法示例:

matchOverlap('12345', /\D{3}/)      // []
matchOverlap('12345', /\d{3}/)      // ["123", "234", "345"]
matchOverlap('12345', /\d{3}/g)     // ["123", "234", "345"]
matchOverlap('1234 5678', /\d{3}/)  // ["123", "234", "567", "678"]
matchOverlap('LOLOL', /lol/)        // []
matchOverlap('LOLOL', /lol/i)       // ["LOL", "LOL"]

答案 4 :(得分:0)

我会考虑不为此使用正则表达式。如果您想分成三组,您可以循环从偏移量开始的字符串:

let s = "12345"
let m = Array.from(s.slice(2), (_, i) => s.slice(i, i+3))
console.log(m)

答案 5 :(得分:-1)

使用(?=(\w{3}))

(3是序列中的字母数)