2017-08-24 90 views
3

下面的代碼不會找到字符串「MOVE」目前在myStr的變量奇怪的行爲

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class Test { 
    public static void main(String[] args) { 
     String myStr = " ELSE MOVE EXT-LNGSHRT-AMT-C TO WK-UNSIGNED-LNGSHRT-AMT COMPUTE WK-SHORT-AMT = EXT-LNGSHRT-AMT-C * -1."; 
     String verbsRegex = "\\s+(ACCEPT|ADD|ALTER|CALL|CANCEL|CLOSE|COMPUTE|DELETE|DISPLAY|DIVIDE|ELSE|EXIT|EVALUATE|EXEC|GO|GOBACK|IF|INITIALIZE|INSPECT|INVOKE|MERGE|MOVE|MULTIPLY|OPEN|PERFORM|READ|RELEASE|RETURN|REWRITE|SEARCH|SET|SORT|START|STOP|STRING|SUBTRACT|UNSTRING|WRITE|COPY|CONTINUE|WHEN)\\s+"; 

     Pattern p = Pattern.compile(verbsRegex); 
     Matcher m = p.matcher(myStr); 
     System.out.println("------------------------------------"); 
     while (m.find()) { 
      System.out.println(myStr.substring(m.start(),m.end())); 
      System.out.println("("+ m.group(1) + ")"); 
     } 
     System.out.println("------------------------------------"); 
    } 
} 

如果我改變myStr的喜歡的東西

 String myStr = " MOVE ELSE MOVE EXT-LNGSHRT-AMT-C TO WK-UNSIGNED-LNGSHRT-AMT COMPUTE WK-SHORT-AMT = EXT-LNGSHRT-AMT-C * -1."; 

的java開始返回我的移動。但在這種情況下,ELSE會錯過!

請解釋這種行爲?我在這裏錯過了很明顯的東西嗎

在此先感謝。

+0

您只捕獲「白色空格後跟任何下列字符串,然後是更多空白區域」,這樣只會對「MOVE」或「ELSE」等文本起作用,但不會「MOVE ELSE」,因爲ELSE不僅僅是前面的白色空間。 – gtgaxiola

+0

你總是打印同一組... – pedromss

回答

1

要打印整場比賽,而不是myStr.substring(m.start(), m.end())可以使用m.group(0)m.group()(兩者是相同的,因爲group()返回結果的group(0))。也看到整個比賽周圍的字符,如[](就像你爲組(1)所做的那樣)。

所以不是

System.out.println(myStr.substring(m.start(),m.end())); 

使用

System.out.println("["+m.group()+"]"); 

,你會看到你所匹配的是[ ELSE ][ COMPUTE ]。正如你所看到的,你也在搜索令牌之後匹配所有可能的空間。但是由於你的正則表達式要求匹配以至少有一個空格開始[MOVE ]不能匹配,因爲沒有未匹配的空白空間。要解決這個問題,你可以使用lookaround mechanism這是zero-length(它不消耗匹配的部分)。

所以不是\\s+(...)\\s+你可以把它改寫爲

(?<=\\s)(...)(?=\\s) 

但它的問題是,您的令牌也需要用空格包圍,所以你將無法找到其被放置在比賽字符串的開始或結束。

解決方案之一可能是\b這是word boundary。它代表地方它要麼開始/字符串的結尾,或放在[a-zA-Z0-9_]和任何非[a-zA-Z0-9_]字符之間,但也將是字母,數字和-之間的地方,所以如果你有IF-ELSE它會單獨找IFELSE即使您希望它被視爲與(...)部分令牌中描述的任何不匹配的單個令牌。

其他解決方案將接受空間,接受由^$(更多信息:http://www.regular-expressions.info/anchors.html)表示的字符串的開始和結束。在這種情況下,您的解決方案可能看起來像

(?<=\\s|^)(...)(?=\\s|$) 

BTW通常我們儘量避免,我們寫(A|AB)情況,因爲如果A足夠匹配整個正則表達式(依賴於正則表達式的其餘部分看起來像)AB將不會被測試。所以如果你有像(A|AB)這樣的正則表達式,那麼對於字符串AAB你會發現兩個匹配,分別是AA,而不是AAB。這就是爲什麼我們通常會試圖從最具體到不太特定的文字寫作,如(AB|A)(或文字的情況下,你可以嘗試根據它們的長度來排序)。

2

而不是使用\s+,你可以用\bWord Boundaries到組中匹配任何詞,所以你的正則表達式應該是這樣的:

\\b(ACCEPT|...|WHEN)\\b 

輸出

------------------------------------ 
ELSE 
(ELSE) 
MOVE 
(MOVE) 
COMPUTE 
(COMPUTE) 
------------------------------------ 
3

\s+在在模式開始時與\s+結束衝突。他們是貪婪的,這意味着它匹配到MOVE這個詞,左邊沒有空白,這意味着它不匹配。

\s+更改爲\s+?MOVE匹配。但請注意,這意味着您要求所有捕獲的組擁有自己的1個或更多空白字符。單詞邊界或環視可以解決這個問題。