2014/02/18

[Regex]Match Overlaping Pattern

情境: 將字串 1 < 20 < 5 < 3 分解成
1 < 20
20 < 5
5 < 3
當利用Regex做字串比對時, 會發現比對是一連串的字串消化行為.
所以若試著使用 (\d+\s*[<>=]+\s*\d+) 這樣的Pattern作比對時, 會發現只能比對到如下的結果:
1 < 20
5 < 3

中間的部分因為20這個數字已經被消化掉, 所以不會再被使用來比對後續的字串.
因此, 為了能達到一開始的目的, 我使用了 Lookahead & Lookbehind.
Pattern:
     (?=(\b\d+\s*[<>=]+\s*\d+\b))
這邊要注意Pattern前後用了 \b 這個符號, 如果沒用此符號, 會多出一個 0 < 5 的Match結果.
有興趣的可以試試, 並想想為什麼.

另外, 因為是用Lookahead的判斷方式, 所以在JavaScript上要小心.
不能用以下的方式, 會產生無窮迴圈:

var re = /(?=(\b\d+\s*[<>=]+\s*\d+\b))/g; 
var str = '11 < 20 < 52 < 311 <11 >111';
var m;
 
while ((m = re.exec(str)) != null) {
    alert(m[1]);
}
要改用以下Shift lastIndex的方式:
var re = /(?=(\b\d+\s*[<>=]+\s*\d+\b))/g; 
var str = '11 < 20 < 52 < 311 <11 >111';
var m;
 
while ((m = re.exec(str)) != null) {
    if (m.index === re.lastIndex) {
        re.lastIndex++;
    }
    alert(m[1]);
}

沒有留言: