2013-02-13 51 views
10

我試圖獲得使用正則表達式的JavaScript字符串所有可能的匹配。看來,我這樣做的方法不匹配已經匹配的字符串的部分。的Javascript正則表達式 - 查找所有可能的匹配,即使在已經拍攝的匹配

變量:

var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'; 

var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g; 

代碼:

var match = string.match(reg); 

所有匹配的結果我得到:

A1B1Y:A1B2Y 
A1B5Y:A1B6Y 
A1B9Y:A1B10Y 

匹配的結果我想:

A1B1Y:A1B2Y 
A1B2Y:A1B3Y 
A1B5Y:A1B6Y 
A1B6Y:A1B7Y 
A1B9Y:A1B10Y 
A1B10Y:A1B11Y 

在我的腦海中,我希望A1B1Y:A1B2YA1B2Y:A1B3Y一起匹配,儘管字符串中的A1B2Y將需要成爲兩個匹配的一部分。

+0

一個超前會讓你得到你想要的比賽,但不幸的是它不會返回預測的部分。我還沒有找到一種方法來捕捉JavaScript的lookahead。也許有,不知道。你的正則表達式是:var reg =/A [0-9] + B [0-9] + Y(?=:A [0-9] + B [0-9] + Y)/ g; – Someone 2013-02-13 21:19:56

+0

@Mantriur:看我的回答... – nhahtdh 2013-02-13 21:22:39

+0

也許'string.split(「:」)'然後遍歷數組可能會給你一個更好的結果。 – Bergi 2013-02-13 21:23:51

回答

20

不修改您的正則表達式,您可以將它設置爲在每次匹配後在比賽的後半部分開始匹配,使用.exec並操縱正則表達式對象的lastIndex屬性。

var string = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y'; 
var reg = /A[0-9]+B[0-9]+Y:A[0-9]+B[0-9]+Y/g; 
var matches = [], found; 
while (found = reg.exec(string)) { 
    matches.push(found[0]); 
    reg.lastIndex -= found[0].split(':')[1].length; 
} 

console.log(matches); 
//["A1B1Y:A1B2Y", "A1B2Y:A1B3Y", "A1B5Y:A1B6Y", "A1B6Y:A1B7Y", "A1B9Y:A1B10Y", "A1B10Y:A1B11Y"] 

Demo


按BERGI的評論,你還可以獲得最後一場比賽的索引和遞增1,以便它,而不是開始從本場比賽的下半場開始匹配,它會開始嘗試從每場比賽的第二個字符開始匹配:

reg.lastIndex = found.index+1; 

Demo

最終結果是一樣的。儘管如此,Bergi的更新代碼稍少一些,並且執行的步驟略爲faster=]

+0

已解決,謝謝! – 2013-02-13 21:22:01

+2

不錯,這比前瞻更好,捕捉組等。順便說一句,'reg.lastIndex = found.index + 1;'應該足夠,並使其表達式不可知 – Bergi 2013-02-13 21:22:37

+0

@VinnieCent沒問題。 '=]'在向上/向下箭頭的下方勾選V,將其標記爲已接受,如果它適合您。哦,謝謝Bergi,不知道那個屬性。 'x]' – 2013-02-13 21:23:35

4

不能從match獲得的直接結果,但它有可能通過RegExp.exec,並與一些修改的正則表達式來生成結果:

var regex = /A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g; 
var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y' 
var arr; 
var results = []; 

while ((arr = regex.exec(input)) !== null) { 
    results.push(arr[0] + arr[1]); 
} 

我以前零寬度積極前瞻(?=pattern)爲了不消耗文本,使重疊部分可以重新匹配。

其實,這是有可能濫用replace方法來做達到相同的結果:

var input = 'A1B1Y:A1B2Y:A1B3Y:A1B4Z:A1B5Y:A1B6Y:A1B7Y:A1B8Z:A1B9Y:A1B10Y:A1B11Y' 
var results = []; 

input.replace(/A[0-9]+B[0-9]+Y(?=(:A[0-9]+B[0-9]+Y))/g, function ($0, $1) { 
    results.push($0 + $1); 
    return ''; 
}); 

然而,由於它是replace,它額外的無用的更換工作。

+0

這也行得通了,謝謝! – 2013-02-13 21:22:25

3

不幸的是,它不像一個簡單的string.match

原因是你想重疊匹配,其中/g標誌不給你。

你可以使用前瞻:

var re = /A\d+B\d+Y(?=:A\d+B\d+Y)/g; 

但現在你會得到:

string.match(re); // ["A1B1Y", "A1B2Y", "A1B5Y", "A1B6Y", "A1B9Y", "A1B10Y"] 

的原因是,向前看是零寬度,也就是說,它只是說,圖案是否自帶之後你'試圖匹配或不匹配;它不包含在比賽中。

您可以使用exec嘗試抓取您想要的東西。如果一個正則表達式有/g標誌,你可以運行exec多次獲得所有的比賽:

// using re from above to get the overlapping matches 

var m; 
var matches = []; 
var re2 = /A\d+B\d+Y:A\d+B\d+Y/g; // make another regex to get what we need 

while ((m = re.exec(string)) !== null) { 
    // m is a match object, which has the index of the current match 
    matches.push(string.substring(m.index).match(re2)[0]); 
} 

matches == [ 
    "A1B1Y:A1B2Y", 
    "A1B2Y:A1B3Y", 
    "A1B5Y:A1B6Y", 
    "A1B6Y:A1B7Y", 
    "A1B9Y:A1B10Y", 
    "A1B10Y:A1B11Y" 
]; 

Here's a fiddle of this in action。打開控制檯來查看結果

或者,您可以通過所產生的陣列上:分割原始的字符串,然後循環,拉出時array[i]array[i+1]比賽都像你想匹配的人。