2011-10-08 56 views
0

考慮以下的正則表達式:爪哇重複圖案匹配(2)

(([^\|])*\|)*([^\|]*) 

這個模式匹配重複的字符串模式的類型

("whatever except |" |) {0 to any times} ("whatever except |" |) {1 time} 

所以應該符合以下的字符串,其具有17的子串(重複16次,加上「z」作爲最後一個)。

"abcd | e | fg | hijk | lmnop | | | qrs | t| uv| w |||||x y| z" 

事實上,RegexPal驗證給定的正則表達式匹配不上面的字符串。

現在,我想要獲得每個子字符串(即「abcd |」,「e |」,「fg |」等),對於它們的數量,長度等沒有預先知識。

根據類似同名previous StackOverflow postMatcherfind()方法的文檔,我只需要像做

Pattern pattern = Pattern.compile(regex); // regex is the above regex 
Matcher matcher = pattern.matcher(input); // input is the above string 

while (matcher.find()) 
{ 
    System.out.println(matcher.group(1)); 
} 

然而,當我這樣做我只是得到2串打印出來:在最後重複的子字符串(「xy |」)和空值;絕對不是我期望的16個子串。

一件很好的事也將是檢查比賽中實際發生,運行find()循環之前,但我不知道是否matches()groupCount() > 0,或其他一些條件,應使用,而不做兩次匹配工作,因爲find()也做匹配。

所以,問題

  1. 我怎樣才能得到所有16個重複子?
  2. 我怎樣才能得到最後一個子字符串?
  3. 如何檢查字符串是否匹配?

回答

1

如果必須使用正則表達式...

1)我怎樣才能得到所有16個重複子?

見下文。騎自行車進行比賽時,你不需要任何東西匹配,只需要你想要的部分。 (我得到17場比賽 - 這是正確的?)

2)我怎樣才能得到最後一個子字符串?

將delim切換到正則表達式的開頭,並允許'^'。

3)我如何檢查字符串是否匹配?

的不匹配什麼資格?任何字符串都會匹配。


下面是使用正則表達式的解決方案:

String input = "abcd | e | fg | hijk | lmnop | | | qrs | t| uv| w |||||x y| z"; 
int expectedSize = 17; 
List<String> expected = new ArrayList<String>(Arrays.asList("abcd ", " e ", " fg ", " hijk ", " lmnop ", " ", " ", " qrs ", " t", " uv", " w ", "", 
    "", "", "", "x y", " z")); 

List<String> matches = new ArrayList<String>(); 

// Pattern pattern = Pattern.compile("(?:\\||^)([^\\|]*)"); 
Pattern pattern = Pattern.compile("(?:_?\\||^)([^\\|]*?)(?=_?\\||$)"); // Edit: allows _| or | as delim 

for (Matcher matcher = pattern.matcher(input); matcher.find();) 
{ 
    matches.add(matcher.group(1)); 
} 

for (int idx = 0, len = matches.size(); idx < len; idx++) 
{ 
    System.out.format("[%-2d] \"%s\"%n", idx + 1, matches.get(idx)); 
} 

assertSame(expectedSize, matches.size()); 
assertEquals(expected, matches); 

輸出

[1 ] "abcd " 
[2 ] " e " 
[3 ] " fg " 
[4 ] " hijk " 
[5 ] " lmnop " 
[6 ] " " 
[7 ] " " 
[8 ] " qrs " 
[9 ] " t" 
[10] " uv" 
[11] " w " 
[12] "" 
[13] "" 
[14] "" 
[15] "" 
[16] "x y" 
[17] " z" 
+0

非常感謝您的出色解決方案!我可以要求稍微擴展嗎?分隔符有時以下劃線(_)作爲前綴,給出_ |在子串之間,除了當子串是空的時候,在這種情況下它不會出現。所以情況可能像「abcd _ | e || fg _ |||| hij」。換句話說,我們在|之前有一個「可選」下劃線並且我想在出現時關閉它(它不出現在子字符串中)。我試着修改你的正則表達式,但是我想出了什麼都沒有奏效。 – PNS

+0

@PNS:所以使用'\ G([^ \ |] +?)_?\ || \ G()\ || \ G([^ \ |] *)$'並且獲得非空的組作爲你的文字。第一部分包含非空數據後跟一個分隔符,第二部分包含空數據後跟一個分隔符,第三部分包含最後一部分數據。 – maaartinus

+0

@PNS,上面的更新模式 – TJR

4

恐怕你讓事情混淆不清。無論何時使用重複('*','+'等),都無法獲得所有匹配的實例。使用類似((xxx)*)的東西,你可以得到整個字符串匹配爲group(1),最後一部分匹配爲group(2),沒有別的。

考慮使用String.split或更好的番石榴的Splitter


廣告1.你不能。使用簡單模式,如

\G([^\|])*(\||$) 

find()一起獲取所有匹配的順序。請注意0​​與之前的比賽有關。


廣告2.我怎樣才能得到最後一個子字符串?

至於最後的結果find回報。


廣告3.如何檢查字符串是否匹配?

你最後find檢查,如果matcher.end() == input.length後。但有了這種模式,你不需要檢查任何東西,因爲它總是匹配。

+0

我不知道這是如何工作的,但感謝。所以,find()會遍歷所有的匹配! – PNS

+0

我的模式比你的模式簡單,所以你缺少哪部分? '\ G'確保您的下一場比賽在您的前一場比賽結束時開始。第一組是指非管道上的任何數字,第二組意味着管道或末端。您可能想使用'\ Z'或'\ z'而不是'$'。 – maaartinus