我怎样才能匹配重叠的string与正则expression式?

假设我有string

"12345" 

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

你不能单独使用正则expression式,但是你可以非常接近:

 var pat = /(?=(\d{3}))\d/g; var results = []; var match; while ( (match = pat.exec( '1234567' ) ) != null ) { results.push( match[1] ); } console.log(results); 

expression式匹配时,通常会消耗匹配的字符。 所以,expression式匹配123 ,剩下的只有45 ,与模式不匹配。

与全局标志正则expression式string#matchstring#match返回一个匹配的子串数组。 /\d{3}/g正则expression式匹配并消耗 (= 读入缓冲区并将其索引前进到当前匹配的字符之后的位置 )3位数序列。 因此,在“吃完” 123 ,索引位于3之后,唯一留给parsing的子string是45在这里不匹配。

我认为在regex101.com使用技术在这里也是值得考虑的:使用一个零宽度断言(一个捕获组的正面向前看)来testinginputstring内的所有位置。 在每次testing之后,“手动”提前RegExp.lastIndex (这是正则expression式的读/写整数属性,指定开始下一次匹配的索引),以避免无限循环。

注意这是一种在.NET( Regex.Matches ),Python( re.findall ),PHP( preg_match_all )中实现的技术。

这里是一个演示:

 var re = /(?=(\d{3}))/g; var str = '12345'; var res = []; var m; while ((m = re.exec(str)) !== null) { if (m.index === re.lastIndex) { re.lastIndex++; } res.push(m[1]); } document.body.innerHTML = JSON.stringify(res); 

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

 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:

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

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

(3是序列中的字母数)