[英]How can I match overlapping strings with regex?
假設我有字符串
"12345"
如果我.match(/\\d{3}/g)
,我只會得到一場比賽, "123"
。 為什么我沒有得到[ "123", "234", "345" ]
?
帶有全局標志正則表達式的string#match
返回一個匹配的 substrings數組。 /\\d{3}/g
正則表達式匹配並消耗(=讀入緩沖區並將其索引推進到當前匹配字符之后的位置)3 位數字序列。 因此,在“吃掉” 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 處理顛簸。
此代碼改編自此答案。 我會將這個問題標記為該問題的重復,但 OP 接受了另一個較小的答案。
當一個表達式匹配時,它通常會消耗它匹配的字符。 因此,在表達式匹配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 是序列中的字母數)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.