查找子串的最高性能

时间:2013-03-08 20:59:51

标签: java string search

我有一个字符串数组(关键字),我需要检查一个更大的字符串中存在多少个字符串(从文件中读取的文本)。我需要检查不区分大小写。 在这一刻,我所做的就是:

private void findKeywords() {
        String body = email.getMessage();
        for (String word : keywords) {
            if (body.toLowerCase().contains(word.toLowerCase())) {
                //some actions                }
            if (email.getSubject().contains(word)) {
                //some actions
            }
        }
    }

从这里阅读问题,另一个解决方案出现了:

private void findKeywords() {
        String body = email.getMessage();
        for (String word : keywords) {
            boolean body_match = Pattern.compile(Pattern.quote(word), Pattern.CASE_INSENSITIVE).matcher(body).find();
            boolean subject_match = Pattern.compile(Pattern.quote(word), Pattern.CASE_INSENSITIVE).matcher(email.getSubject()).find();
            if (body_match) {
                rating++;
            }
            if (subject_match) {
                rating++;
            }
        }
    }

哪些解决方案效率更高?还有另一种方法可以做到这一点更好吗?任何可接受的解决方案都必须易于实现(与上述相同),最好没有外部库,因为在这种情况下这不是一个非常重要的问题。

4 个答案:

答案 0 :(得分:2)

这两种解决方案对我来说都是可行的。我建议的一个改进是将函数移出循环。在您当前的代码中,您反复执行诸如toLowerCase()和Pattern.compile之类的操作,您只需执行一次。

显然,有更快的方法可以解决这个问题,但它们需要比这些5行更复杂的代码。

答案 1 :(得分:1)

更好:使用所有关键字构建单一模式。然后搜索该模式。假设您的关键字不包含元字符(模式中具有特殊含义的字符),请使用:

StringBuilder keywordRegex = new StringBuilder();
for (String w : keywords) {
   keywordRegex.append("|"+w);
}
Pattern p = Pattern.compile(keywordRegex.substring(1));
Matcher m = new p.matcher(textToMatch);
while (m.find()) {
    // match is at m.start(); word is m.group(0);
}

比迭代所有关键字更有效:模式编译(一次)将生成一个自动搜索,一次查找所有关键字。

答案 2 :(得分:0)

我认为你提到的显式正则表达式解决方案会更有效率,因为它没有toLowerCase操作,它会将输入字符串复制到内存中并使字符小写。

这两种解决方案都应该是实用的,你的问题主要是学术性的,但我认为正则表达式提供了更清晰的代码。

答案 3 :(得分:0)

如果您的电子邮件正文非常大,编写一个专门的不区分大小写的包含可能是合理的,因为您可以避免在大字符串上调用toUpperCase():

static bool containsIgnoreCase(String big, String small) {
  if (small == null || big == null || small.length() > big.length()) {
    return false;
  }      
  String smallLC = small.toLowerCase();
  String smallUC = small.toUpperCase();
  for (int i = 0; i < big.length(); ++i) {
    if (matchesAt(big, i, smallLC, smallUC)) {
      return true;
    }
  }
  return false;
}

private static bool matchesAt(String big, int index, String lc, String uc) {
  if (index + lc.length() > big.length()) {
    return false;
  }
  for (int i = 0; i < lc.length(); ++i) {
    char c = big.charAt(i + index);
    if ((c != lc.charAt(i)) && (c != uc.charAt(i))) {
      return false;
    }
  }
  return true;
}