以下代码未在myStr变量中找到字符串“MOVE”
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开始给我回复MOVE。但在这种情况下,ELSE错过了!
对此行为有任何解释吗?我错过了一些明显的东西吗?
提前致谢。
答案 0 :(得分:3)
最后的\s+
在模式开头与\s+
冲突。它们是贪婪的,这意味着它匹配单词MOVE
,在它的左边没有留下空格,这意味着它不匹配。
将\s+
更改为\s+?
和MOVE
匹配。但要注意,这意味着您要求所有捕获的组拥有自己的1个或多个空白字符。单词边界或外观可以解决这个问题。
答案 1 :(得分:2)
您可以使用\s+
Word Boundaries来匹配组中的任何字词,而不是使用\b
,因此您的正则表达式应如下所示:
\\b(ACCEPT|...|WHEN)\\b
<强>输出强>
------------------------------------
ELSE
(ELSE)
MOVE
(MOVE)
COMPUTE
(COMPUTE)
------------------------------------
答案 2 :(得分: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。它代表 place ,它是字符串的开头/结尾,或者放在[a-zA-Z0-9_]
和任何非[a-zA-Z0-9_]
字符之间,但这也代表字母字符和-
所以,如果您有IF-ELSE
,即使您希望将其视为不符合任何描述的单个令牌,它也会单独找到IF
和ELSE
在(...)
部分代币中。
其他解决方案是接受空格,接受由^
和$
表示的字符串的开头和结尾(更多信息位于:http://www.regular-expressions.info/anchors.html)。在这种情况下,您的解决方案可能看起来像
(?<=\\s|^)(...)(?=\\s|$)
BTW通常我们会尽量避免写(A|AB)
的情况,因为如果A
足够来匹配整个正则表达式(取决于正则表达式的其余部分){ {1}}将不会被测试。因此,如果您有AB
等正则表达式,那么对于字符串(A|AB)
,您会发现两个匹配项AAB
和A
,而不是A
和A
}。这就是为什么我们通常会尝试将其从最具体到更不具体的内容写成AB
(或者在文字的情况下,您可以尝试根据它们的长度对它们进行排序)。