2017-08-24 58 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个或更多空白字符。单词边界或环视可以解决这个问题。