【问题标题】:Java find value in a string using regexJava使用正则表达式在字符串中查找值
【发布时间】:2017-05-26 18:36:28
【问题描述】:

我想知道在 java 中使用 matcher 的行为。

我有一个我编译的模式,当运行匹配器的结果时,我不明白为什么缺少特定值。

我的代码:

String str = "star wars";
Pattern p = Pattern.compile("star war|Star War|Starwars|star wars|star wars|pirates of the caribbean|long strage trip|drone|snatched (2017)");
Matcher matcher = p.matcher(str);
while (matcher.find()) {
        System.out.println("\nRegex : " matcher.group());
    }

我被“星球大战”击中,这在我的模式中是正确的。

但我不喜欢“星球大战”,我不明白为什么,因为它是我模式的一部分。

【问题讨论】:

  • 交替组中匹配“wins”的第一个备选方案,其余不检查。一旦star war 被匹配,文本就被消费了,不会再有任何传球。这是预期的。你需要什么行为?
  • 有没有办法返回所有点击?
  • 您必须分别对照字符串检查每个模式,而不是一长串交替。
  • 明白..谢谢大家
  • ideone.com/gGcALb。顺便说一句,你有 2 个“星球大战”:)

标签: java regex java-8


【解决方案1】:

这种行为是意料之中的,因为 NFA 正则表达式中的 alternation 是“渴望”的,即第一场比赛获胜,其余的替代方案甚至都没有经过测试。另外,请注意,一旦正则表达式引擎在消费模式中找到匹配项(并且您的模式是消费模式,它不是像前瞻/后视/单词边界/锚点那样的零宽度断言),索引就会前进到末尾从该位置搜索匹配和下一个匹配。

因此,一旦您的第一个 star war 替代分支匹配,就无法匹配 star wars,因为正则表达式索引在最后一个 s 之前。

只需检查字符串是否包含您要检查的字符串,最简单的方法是使用循环:

String str = "star wars";
String[] arr = {"star war","Star War","Starwars","star wars","pirates of the caribbean","long strage trip","drone","snatched (2017)"};
for(String s: arr){
    if(str.contains(s))
        System.out.println(s);
}

Java demo

顺便说一句,您的正则表达式包含snatched (2017),它不匹配(),它只匹配snatched 2017。要匹配文字括号,必须对 () 进行转义。我还删除了 star wars 的欺骗条目。

【讨论】:

  • 这种方法更好,但是我们也应该在|上拆分字符串并完全匹配str,以避免像AI这样的电影出现问题。
  • @steffen:我与\| 分开只是为了快速构建一个数组。我认为最好的方法是像往常一样定义它,使用String[] arr = {"term1", "term2", "etc."};。请注意,我什至没有删除受骗者,我猜那些是在设计时提供的。
  • 我决定编辑答案以显示应如何定义搜索词数组。与 "\\|" 拆分是 hacky。
【解决方案2】:

构建正则表达式的更好方法如下:

String pattern = "[Ss]tar[\\s]{0,1}[Ww]ar[s]{0,1}";

分解:

  • [Ss]:它将匹配第一个位置的 S 或 s
  • \s:空间表示
  • {0,1}:前一个字符(或集合)将匹配 0 到 1 次

另一种选择是:

String pattern = "[Ss]tar[\\s]?[Ww]ar[s]?";
  • ?:前一个字符(或集合)将匹配一次或根本不匹配

欲了解更多信息,请参阅https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

编辑 1:修正错字 (\s -> \\s)。谢谢,@eugene。

【讨论】:

  • [\s]{0,1} 应该是\\s+ 可能有很多空格
  • Eugene: * 会导致匹配 0 次或更多次。通过使用 {0,1} 表示仅匹配 0 或 1 次。
  • @Eugene - '\\s*' 也可以匹配“星球大战”之类的内容。
  • @marklark,是的,我知道。我只是想指出一种比问题中更好的方法来构建正则表达式。事实上,这是我回答的第一行。
【解决方案3】:

你想匹配整个输入序列,所以你应该使用Matcher.matches()或添加^$

Pattern p = Pattern.compile("^(star war|Star War|Starwars|star wars|"
        + "star wars|pirates of the caribbean)$");

将打印

Regex : star wars

但我同意@NAMS:不要像这样构建你的正则表达式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 2012-10-31
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多