【问题标题】:How to find a whole word in a String in Java?如何在 Java 中的字符串中查找整个单词?
【发布时间】:2011-07-02 17:46:39
【问题描述】:

我有一个必须为不同关键字解析的字符串。 例如,我有字符串:

“我会来123woods见你”

我的关键字是

'123woods'
'树林'

每当我有比赛和地点时,我都应该报告。还应考虑多次出现。

但是,对于这个,我应该只在 '123woods' 上得到匹配,而不是在 'woods' 上得到匹配。这消除了使用String.contains() 方法。此外,我应该能够拥有一个关键字列表/组,并同时检查它们的出现。在这个例子中,如果我有 '123woods''come',我应该得到两次。在大文本上,方法执行应该有点快。

我的想法是使用StringTokenizer,但我不确定它是否会表现良好。有什么建议吗?

【问题讨论】:

  • 你确定逻辑没有缺陷吗?如果您有关键字 - words123 和 123words。那么在文本 words123words 中有哪些匹配项?
  • 无。我只需要完全匹配的单词。

标签: java string pattern-matching stringtokenizer


【解决方案1】:

以下示例基于您的 cmets。它使用关键字列表,将使用单词边界在给定的字符串中搜索。它使用来自 Apache Commons Lang 的 StringUtils 来构建正则表达式并打印匹配的组。

String text = "I will come and meet you at the woods 123woods and all the woods";

List<String> tokens = new ArrayList<String>();
tokens.add("123woods");
tokens.add("woods");

String patternString = "\\b(" + StringUtils.join(tokens, "|") + ")\\b";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);

while (matcher.find()) {
    System.out.println(matcher.group(1));
}

如果您正在寻找更高的性能,您可以查看StringSearch:Java 中的高性能模式匹配算法。

【讨论】:

  • 如果我有一个 ArrayList 并且我想使用 Pattern 来构建它怎么办?看来我必须使用值得信赖的旧 StringBuilder?
  • @baba - 你可以这样做,或者你可以遍历列表。我不确定哪种方法更有效,如果性能受到关注,您可能需要尝试这两种方法。
  • 就个人而言,我更喜欢遍历列表。将此选项添加到我的答案中。
  • @baba:现在我开始看到了。我根据您的评论更新了我的答案。
  • 使用 Java 8,不再需要 StringUtilsString 有静态的 join() 方法可以完成这项工作。
【解决方案2】:

按照其他人的回答使用正则表达式 + 单词边界。

"I will come and meet you at the 123woods".matches(".*\\b123woods\\b.*");

会是真的。

"I will come and meet you at the 123woods".matches(".*\\bwoods\\b.*");

会是假的。

【讨论】:

    【解决方案3】:

    希望这对你有用:

    String string = "I will come and meet you at the 123woods";
    String keyword = "123woods";
    
    Boolean found = Arrays.asList(string.split(" ")).contains(keyword);
    if(found){
          System.out.println("Keyword matched the string");
    }
    

    http://codigounico.blogspot.com/

    【讨论】:

      【解决方案4】:

      Arrays.asList(String.split(" ")).contains("xx") 之类的怎么样?

      参见String.split()How can I test if an array contains a certain value

      【讨论】:

        【解决方案5】:

        有一种方法可以在 Android 中从 String匹配 精确字词

        String full = "Hello World. How are you ?";
        
        String one = "Hell";
        String two = "Hello";
        String three = "are";
        String four = "ar";
        
        
        boolean is1 = isContainExactWord(full, one);
        boolean is2 = isContainExactWord(full, two);
        boolean is3 = isContainExactWord(full, three);
        boolean is4 = isContainExactWord(full, four);
        
        Log.i("Contains Result", is1+"-"+is2+"-"+is3+"-"+is4);
        
        Result: false-true-true-false
        

        匹配词功能:

        private boolean isContainExactWord(String fullString, String partWord){
            String pattern = "\\b"+partWord+"\\b";
            Pattern p=Pattern.compile(pattern);
            Matcher m=p.matcher(fullString);
            return m.find();
        }
        

        完成

        【讨论】:

          【解决方案6】:
          public class FindTextInLine {
              String match = "123woods";
              String text = "I will come and meet you at the 123woods";
          
              public void findText () {
                  if (text.contains(match)) {
                      System.out.println("Keyword matched the string" );
                  }
              }
          }
          

          【讨论】:

          • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
          【解决方案7】:

          尝试使用正则表达式进行匹配。匹配“\b123wood\b”,\b是一个分词。

          【讨论】:

            【解决方案8】:

            该解决方案似乎已被长期接受,但该解决方案可以改进,所以如果有人遇到类似问题:

            这是多模式搜索算法的经典应用。

            Java 模式搜索(使用Matcher.find)不适合这样做。在 java 中优化了精确搜索一个关键字,搜索 or 表达式使用正则表达式非确定性自动机,该自动机在不匹配时回溯。在更坏的情况下,文本的每个字符将被处理 l 次(其中 l 是模式长度的总和)。

            单一模式搜索更好,但也不合格。必须开始对每个关键字模式进行整个搜索。在更糟糕的情况下,文本的每个字符将被处理 p 次,其中 p 是模式的数量。

            多模式搜索将只处理文本的每个字符一次。适合这种搜索的算法是 Aho-Corasick、Wu-Manber 或 Set Backwards Oracle Matching。这些可以在 Stringsearchalgorithmsbyteseek 等库中找到。

            // example with StringSearchAlgorithms
            
            AhoCorasick stringSearch = new AhoCorasick(asList("123woods", "woods"));
            
            CharProvider text = new StringCharProvider("I will come and meet you at the woods 123woods and all the woods", 0);
            
            StringFinder finder = stringSearch.createFinder(text);
            
            List<StringMatch> all = finder.findAll();
            

            【讨论】:

              【解决方案9】:

              一个更简单的方法是使用 split():

              String match = "123woods";
              String text = "I will come and meet you at the 123woods";
              
              String[] sentence = text.split();
              for(String word: sentence)
              {
                  if(word.equals(match))
                      return true;
              }
              return false;
              

              这是一种更简单、不那么优雅的方式来做同样的事情,而不使用令牌等。

              【讨论】:

              • 虽然更易于理解和编写,但这不是我所问问题的答案。我有两个或三个,或者可能是不定数量的“匹配”关键字,我需要获取那些在“文本”中找到的关键字。当然,您可能会为拆分文本上的每个“单词”循环我的“匹配”关键字,但我发现它远没有已经接受的解决方案那么优雅。
              【解决方案10】:

              您可以使用正则表达式。 使用 Matcher 和 Pattern 方法获得所需的输出

              【讨论】:

                【解决方案11】:

                您还可以使用带有 \b 标志(整个单词边界)的正则表达式匹配。

                【讨论】:

                  【解决方案12】:

                  要匹配 "123woods" 而不是 "woods" ,请在正则表达式中使用原子分组。 需要注意的一点是,在单独匹配“123woods”的字符串中,它将匹配第一个“123woods”并退出,而不是进一步搜索相同的字符串。

                  \b(?>123woods|woods)\b
                  

                  它搜索 123woods 作为主要搜索,一旦匹配就退出搜索。

                  【讨论】:

                    【解决方案13】:

                    回顾最初的问题,我们需要在给定的句子中找到一些给定的关键字,计算出现的次数并知道在哪里。我不太明白“哪里”是什么意思(它是句子中的索引吗?),所以我会通过那个......我还在学习java,一次一步,所以我会看到在适当的时候给那个:-)

                    必须注意,普通句子(如原始问题中的句子)可以有重复的关键字,因此搜索不能只询问给定关键字“是否存在”,如果存在则将其计为 1。可以有多个相同的。例如:

                    // Base sentence (added punctuation, to make it more interesting):
                    String sentence = "Say that 123 of us will come by and meet you, "
                                    + "say, at the woods of 123woods.";
                    
                    // Split it (punctuation taken in consideration, as well):
                    java.util.List<String> strings = 
                                           java.util.Arrays.asList(sentence.split(" |,|\\."));
                    
                    // My keywords:
                    java.util.ArrayList<String> keywords = new java.util.ArrayList<>();
                    keywords.add("123woods");
                    keywords.add("come");
                    keywords.add("you");
                    keywords.add("say");
                    

                    通过查看,“Say”+“come”+“you”+“say”+“123woods”的预期结果将是 5,如果我们使用小写字母,则计算“say”两次。如果我们不这样做,那么计数应该是 4,“说”被排除在外,“说”被包括在内。美好的。我的建议是:

                    // Set... ready...?
                    int counter = 0;
                    
                    // Go!
                    for(String s : strings)
                    {
                        // Asking if the sentence exists in the keywords, not the other
                        // around, to find repeated keywords in the sentence.
                        Boolean found = keywords.contains(s.toLowerCase());
                        if(found)
                        {
                            counter ++;
                            System.out.println("Found: " + s);
                        }
                    }
                    
                    // Statistics:
                    if (counter > 0)
                    {
                        System.out.println("In sentence: " + sentence + "\n"
                                         + "Count: " + counter);
                    }
                    

                    结果是:

                    找到:Say
                    发现:来
                    找到:你
                    找到:说
                    发现:123woods
                    在句子中:说我们中的 123 个人会过来和你见面,比如说,在 123woods 的树林里。
                    计数:5

                    【讨论】:

                      猜你喜欢
                      • 2017-07-26
                      • 1970-01-01
                      • 2015-12-16
                      • 2011-05-08
                      • 2022-12-15
                      • 2022-01-06
                      • 2012-10-30
                      • 1970-01-01
                      相关资源
                      最近更新 更多