假设我有一个字符串
"12345"
如果我使用.match(/\d{3}/g)
,我只会得到一个匹配项:"123"
。为什么我没有得到[ "123", "234", "345" ]
?
假设我有一个字符串
"12345"
如果我使用.match(/\d{3}/g)
,我只会得到一个匹配项:"123"
。为什么我没有得到[ "123", "234", "345" ]
?
string#match
带有全局标志的正则表达式返回一个匹配的子字符串数组。正则表达式 /\d{3}/g
匹配并“消耗”(即读入缓冲区并将其索引提前到当前匹配字符右侧位置)三位数字序列。因此,在“吃掉”123
后,索引位于3
之后,唯一剩下的可用于解析的子字符串为45
- 这里没有匹配。
我认为在regex101.com使用的技术在这里也值得考虑:使用零宽度断言(具有捕获组的正向先行断言)来测试输入字符串内的所有位置。每次测试后,RegExp.lastIndex
(它是一个正则表达式的读/写整数属性,指定下一个匹配的开始索引)手动“推进”,以避免无限循环。
请注意,这是一种在.NET (Regex.Matches
)、Python (re.findall
)、PHP (preg_match_all
)、Ruby (String#scan
) 中实现的技术,也可以在Java中使用。这里是使用matchAll
的演示:
var re = /(?=(\d{3}))/g;
console.log( Array.from('12345'.matchAll(re), x => x[1]) );
这是一个符合ES5标准的演示:
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演示
请注意,可以使用“常规”消耗\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);
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处理推进。当一个表达式匹配时,通常会“消耗”匹配的字符。因此,在表达式匹配123
之后,只剩下不匹配模式的45
。
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"]
let s = "12345"
let m = Array.from(s.slice(2), (_, i) => s.slice(i, i+3))
console.log(m)
使用 (?=(\w{3}))
(3 为序列中字母的数量)
"123"
已经匹配到了,所以你只能得到一个匹配,而剩下的字符"45"
不匹配。如果你使用/\d{2}/g
,那么你将会得到['12','34']
。无论如何,在 Stack Overflow 中有一个答案可以获得重叠的匹配字符串:https://dev59.com/-GUq5IYBdhLWcg3wBLw-#14863268 - EfrainReyes