使用 Java Regex,如何检查字符串是不是包含集合中的任何单词?

Posted

技术标签:

【中文标题】使用 Java Regex,如何检查字符串是不是包含集合中的任何单词?【英文标题】:Using Java Regex, how to check if a string contains any of the words in a set ?使用 Java Regex,如何检查字符串是否包含集合中的任何单词? 【发布时间】:2012-03-19 21:55:46 【问题描述】:

我有一组词说——苹果、橙子、梨、香蕉、猕猴桃

我想检查一个句子是否包含上面列出的任何单词,如果是,我想找到匹配的单词。如何在 Regex 中完成此操作?

我目前正在为我的每组单词调用 String.indexOf()。我假设这不如正则表达式匹配有效?

【问题讨论】:

【参考方案1】:

我认为正则表达式不会在性能方面做得更好,但您可以按如下方式使用它:

Pattern p = Pattern.compile("(apple|orange|pear)");
Matcher m = p.matcher(inputString);
while (m.find()) 
   String matched = m.group(1);
   // Do something

【讨论】:

性能取决于正则表达式的长度。如果少于 1000 个字符,请继续。如果它更长,您需要其他解决方案。例如,将文本拆分为单独的单词,并根据预定义的哈希表/“已知”单词集检查它们。 @deporter 答案的目的是就如何解决问题提供一个很好的提示,而不是提供一个完美、闪亮、世界级的解决方案。它可以很容易地改进,就可读性而言,如果您有 200 个字符串(不使用正则表达式的另一个原因),您可以使用 for 循环并在 StringBuilder 中连接。我认为我的回答提供了足够的味道。 您的意思可能是“(苹果)|(橙色)|(梨)”。否则,您将匹配 applorangeear 或 applerangpear 之类的内容。 哼没有。对不起,但它就是这样工作的。您的解决方案也可以,但是您必须为每个单词使用不同的组 @GuillaumePolet 添加单词边界"\\b(apple|orange|pear)\\b"【参考方案2】:

TL;DR 对于简单的子字符串contains() 是最好的,但对于只匹配整个单词正则表达式可能更好。

查看哪种方法更有效的最佳方法是对其进行测试。

您可以使用String.contains() 代替String.indexOf() 来简化您的非正则表达式代码。

要搜索不同的单词,正则表达式如下所示:

apple|orange|pear|banana|kiwi

| 在正则表达式中用作OR

我非常简单的测试代码如下所示:

public class TestContains 

   private static String containsWord(Set<String> words,String sentence) 
     for (String word : words) 
       if (sentence.contains(word)) 
         return word;
       
     

     return null;
   

   private static String matchesPattern(Pattern p,String sentence) 
     Matcher m = p.matcher(sentence);

     if (m.find()) 
       return m.group();
     

     return null;
   

   public static void main(String[] args) 
     Set<String> words = new HashSet<String>();
     words.add("apple");
     words.add("orange");
     words.add("pear");
     words.add("banana");
     words.add("kiwi");

     Pattern p = Pattern.compile("apple|orange|pear|banana|kiwi");

     String noMatch = "The quick brown fox jumps over the lazy dog.";
     String startMatch = "An apple is nice";
     String endMatch = "This is a longer sentence with the match for our fruit at the end: kiwi";

     long start = System.currentTimeMillis();
     int iterations = 10000000;

     for (int i = 0; i < iterations; i++) 
       containsWord(words, noMatch);
       containsWord(words, startMatch);
       containsWord(words, endMatch);
     

     System.out.println("Contains took " + (System.currentTimeMillis() - start) + "ms");
     start = System.currentTimeMillis();

     for (int i = 0; i < iterations; i++) 
       matchesPattern(p,noMatch);
       matchesPattern(p,startMatch);
       matchesPattern(p,endMatch);
     

     System.out.println("Regular Expression took " + (System.currentTimeMillis() - start) + "ms");
   

我得到的结果如下:

Contains took 5962ms
Regular Expression took 63475ms

显然,时间会根据要搜索的单词数和要搜索的字符串而有所不同,但对于像这样的简单搜索,contains() 似乎比正则表达式快 10 倍左右。

通过使用正则表达式在另一个字符串中搜索字符串,您正在使用大锤来破解一个坚果,所以我想我们不应该对它的速度感到惊讶。当您要查找的模式更复杂时保存正则表达式。

您可能想要使用正则表达式的一种情况是,如果 indexOf()contains() 无法完成这项工作,因为您只想匹配整个单词,而不仅仅是子字符串,例如你想匹配pear,而不是spears。正则表达式可以很好地处理这种情况,因为它们具有word boundaries 的概念。

在这种情况下,我们会将模式更改为:

\b(apple|orange|pear|banana|kiwi)\b

\b 表示只匹配单词的开头或结尾,括号将 OR 表达式组合在一起。

注意,在您的代码中定义此模式时,您需要使用另一个反斜杠来转义反斜杠:

 Pattern p = Pattern.compile("\\b(apple|orange|pear|banana|kiwi)\\b");

【讨论】:

【参考方案3】:

这是我找到的最简单的解决方案(用通配符匹配):

boolean a = str.matches(".*\\b(wordA|wordB|wordC|wordD|wordE)\\b.*");

【讨论】:

以上是关于使用 Java Regex,如何检查字符串是不是包含集合中的任何单词?的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用“Regex”检查字符串数组中是不是存在元素

如何使用 RegEx 检查表单输入是不是以 .pdf 结尾

fmt 库:如何使用 RegEx 添加编译时字符串检查?

如何使用正则表达式检查用户输入是不是仅包含特殊字符?

如何检查字符串是不是包含从 a 到 z 的任何字母? [复制]

Python RegEx