-1

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

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

4 回答 4

2

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

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

于 2013-03-08T21:08:49.300 回答
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);
}

比遍历所有关键字更有效:模式编译(一次)将生成一个自动查找所有关键字的自动机。

于 2013-03-08T21:15:18.797 回答
0

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

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

于 2013-03-08T21:10:50.373 回答
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;
}
于 2013-03-08T21:28:43.247 回答