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

Javascript 如何将重叠字符串与正则表达式匹配?,javascript,regex,Javascript,Regex,假设我有绳子 "12345" 如果我.match(/\d{3}/g),我只得到一个匹配项,“123”。为什么我得不到[“123”、“234”、“345”]?当表达式匹配时,它通常使用匹配的字符。因此,在表达式匹配123后,只剩下45,这与模式不匹配。要回答“如何”,可以手动更改最后一个匹配的索引(需要循环): 为了方便起见,这里有一个函数: function matchOverlap(input, re) { var r = [], m; // prevent infinite

假设我有绳子

"12345"

如果我
.match(/\d{3}/g)
,我只得到一个匹配项,
“123”
。为什么我得不到
[“123”、“234”、“345”]

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

要回答“如何”,可以手动更改最后一个匹配的索引(需要循环):

为了方便起见,这里有一个函数:

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"]

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

var pat=/(?=(\d{3}))\d/g;
var结果=[];
var匹配;
while((match=pat.exec('1234567'))!=null){
结果:推(匹配[1]);
}
控制台日志(结果)
带有全局标志regex的
字符串#match
返回匹配的子字符串数组。
/\d{3}/g
正则表达式匹配并使用(=读入缓冲区并将其索引前进到当前匹配字符后面的位置)3位序列。因此,在“吃掉”
123
之后,索引位于
3
之后,唯一剩下的用于解析的子字符串是
45
——此处不匹配

我认为在中使用的技术也值得考虑:使用零宽度断言(捕获组的正向前瞻)来测试输入字符串中的所有位置。在每次测试之后,“手动”推进(它是正则表达式的读/写整数属性,指定开始下一次匹配的索引)以避免无限循环

注意,它是一种在.NET(
Regex.Matches
)、Python(
re.findall
)、PHP(
preg\u match\u all
)、Ruby(
String#scan
)中实现的技术,也可以在Java中使用。 下面是一个使用
matchAll
的演示:

var re=/(?=(\d{3}))/g;
log(Array.from('12345'.matchAll(re),x=>x[1])使用
(?=(\w{3}))


(3是序列中的字母数)

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

s=“12345”
设m=Array.from(s.slice(2),(u,i)=>s.slice(i,i+3))

console.log(m)
您只获得一个匹配项,因为
“123”
已匹配,而剩余字符
“45”
不匹配。如果您使用
/\d{2}/g
,您将得到
['12','34']
。无论如何,在中有一个答案,即使它们重叠也可以得到匹配的字符串:因为while循环的条件永远不会改变,所以源代码会产生一个无止境的循环。。。正如@Wiktor Stribiżew在他的回答中已经提到的,必须更改regex对象的索引才能更改匹配结果。哦,是的,谢谢你的提示!删除了相关评论:“我认为最后一个源代码块中有一个小错误:不是res.push(m[0]);必须使用res.push(m[1]);因为匹配结果存储在数组m的索引1而不是索引0中”
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"]