在Java中匹配字符串中的单词

4
我正在尝试在Java中匹配包含单词"#SP"(不区分大小写,不带引号)的字符串。然而,我发现使用正则表达式非常困难!
需要匹配的字符串: "This is a sample #sp string""#SP string text...""String text #Sp" 不需要匹配的字符串: "Anything with #Spider""#Spin #Spoon #SPORK" 这是我目前的代码:http://ideone.com/B7hHkR。有人能指导我构建正则表达式吗?
我还尝试过:"\\w*\\s*#sp\\w*\\s*",但没有成功。
编辑:这是来自IDEone的代码:
java.util.regex.Pattern p = 
    java.util.regex.Pattern.compile("\\b#SP\\b", 
        java.util.regex.Pattern.CASE_INSENSITIVE);

java.util.regex.Matcher m = p.matcher("s #SP s");

if (m.find()) {
    System.out.println("Match!");
}

1
在正则表达式中,* 表示“零次或多次”。 - Brian Roach
@BrianRoach 我原以为我使用它是正确的。例如:"这是一个#sp"(在#sp之前多于0次,在#sp之后0次以上),"#sp文本"(在#sp之前0次,在#sp之后多于0次),"#sp"(在之前和之后都为0次) - Marco Pietro Cirillo
1
使用正则表达式时,你只需要匹配你想要匹配的文本。不必担心你想要匹配的文本前面或后面的内容,除非你明确需要。这也是锚点发挥作用的地方,因为它们不会消耗文本:\\b将检测到“单词边界”,但不会消耗单词前/后的字符。 - fge
3个回答

6

(编辑:无需使用正向后查找,只进行匹配而不是替换)

你是Java误命名的正则表达式匹配方法的又一受害者。

.matches()非常不幸地尝试匹配整个输入,这明显违反了“正则表达式匹配”的定义(正则表达式可以在输入的任何位置匹配)。你需要使用的方法是.find()

这是一个愚蠢的API,不幸的是,Java并不是唯一一个拥有这种误导性方法名称的语言。Python也承认有过类似情况。

此外,你还有一个问题,即\\b将检测单词边界,而#不是单词的一部分。你需要使用一个交替项来检测输入的开头或空格。

你的代码应该像这样(非完全限定的类):

Pattern p = Pattern.compile("(^|\\s)#SP\\b", Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher("s #SP s");

if (m.find()) {
    System.out.println("Match!");
}

"?<=^" 这部分是什么意思? - dashrb
非常感谢。但请允许我理解您的正则表达式:?<=^ 意味着匹配“?, <, =或无”? - Marco Pietro Cirillo
1
(?<=...) 是一个正向预查。它是一个锚点,意思是“如果前面的文本符合给定的正则表达式,则尝试开始匹配正则表达式(...)”。诚然,在这里并不需要它,因为只需要匹配而不替换任何内容,所以(^|\\s)就足够了。 - fge

4

你做得很好,但是#前面的\b引导有误导性。 \b是一个词边界,但是#已经不是一个单词字符(即它不在集合[0-9A-Za-z_]中)。 因此,#前面的空格不被视为词边界。 修改为:

java.util.regex.Pattern p = 
    java.util.regex.Pattern.compile("(^|\\s)#SP\\b", 
        java.util.regex.Pattern.CASE_INSENSITIVE);

(^|\s) 的意思是:匹配 ^ 或 \s,其中 ^ 表示字符串的开头(例如,"#SP String"),\s 表示空白字符。

不用谢。 显然你确实需要更改为find()而不是matches(),正如fge所说的那样。 他今天让我们两个都学到了点东西。 - dashrb

1
正则表达式"\\w*\\s*#sp\\w*\s*"将匹配0个或多个单词,后跟0个或多个空格,后跟#sp,后跟0个或多个单词,后跟0个或多个空格。我的建议是不要在表达式中使用\s*来分隔单词,而是使用\b。
"(^|\b)#sp(\b|$)"

这是使用 "\b#SP\b" 的结果:http://ideone.com/DF1dPq它仍然无法匹配字符串。 - Marco Pietro Cirillo
由于某些原因,在Java中的\b单词边界无法匹配字符串的开头或结尾。我已经编辑了我的答案以适应这种情况。 - Will C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接