簡體   English   中英

如何將重疊字符串與正則表達式匹配?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM