31

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

“我会来123woods见你”

我的关键词是

'123 伍兹'
'伍兹'

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

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

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

4

13 回答 13

49

以下示例基于您的评论。它使用关键字列表,将使用单词边界在给定的字符串中搜索。它使用来自 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 中的高性能模式匹配算法。

于 2011-02-23T12:50:43.267 回答
19

正如其他人回答的那样,使用正则表达式 + 单词边界。

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

将是真的。

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

将是错误的。

于 2011-02-23T12:56:34.010 回答
12

希望这对你有用:

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/

于 2011-02-23T14:02:15.047 回答
9

怎么样Arrays.asList(String.split(" ")).contains("xx")

请参阅String.split()如何测试数组是否包含某个值

于 2011-02-23T12:50:35.667 回答
4

有一种方法可以匹配 Android中字符串中的确切单词:

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();
}

完毕

于 2015-07-07T10:51:42.050 回答
4
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" );
        }
    }
}
于 2018-06-21T13:38:36.507 回答
2

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

于 2011-02-23T12:51:38.630 回答
2

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

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

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();
于 2016-08-13T10:22:39.637 回答
1

一个更简单的方法是使用 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;

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

于 2012-10-11T00:12:48.697 回答
0

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

于 2011-02-23T12:49:09.680 回答
0

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

于 2011-02-23T12:51:21.517 回答
0

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

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

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

于 2013-08-31T13:00:55.347 回答
0

回顾最初的问题,我们需要在给定的句子中找到一些给定的关键字,计算出现的次数并知道在哪里。我不太明白“哪里”是什么意思(它是句子中的索引吗?),所以我会通过那个......我还在学习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);
}

结果是:

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

于 2015-07-13T23:54:14.057 回答