首页 > 解决方案 > 在文本中以任意顺序查找一组彼此靠近的单词

问题描述

为了突出显示多个单词的全文搜索的结果,我尝试使用正则表达式来查找具有预定义距离的项目,使用以下正则表达式(两个单词之间的距离最多 100 个字符):

word1(?:\\s|.){1,100}?word2

这会找到word1 ... word2,但不会找到word2...word1 我知道我可以组合两个正则表达式短语,但是如果用户搜索说 6 个单词怎么办?

标签: regexdartfull-text-search

解决方案


我可能不会尝试使用 RegExp 来执行此操作。

如果你想在很短的距离内找到两次出现的n 个单词,那么它仍然是可行的。就像是:

var re = RegExp(r"\b(word1|...|wordn)\b[^]{1,100}\b(?:word1|...|wordn)\b(?<!\b\1)");

这应该找到 word1 到 wordn 中的任何一个,然后是 1-100 个其他字符,然后是 word1 到 wordn 中的另一个(但由于反向后视而不是同一个)。

如果您想以任何顺序查找所有单词,那么这是一个非常不规则的问题,正则表达式真的不适合。您可以将上面的表达式概括为:

RegExp(r"\b(word1|...|word10)\b"
  r"[^]{1,100}\b(word1|...|word10)\b(?<!\b\1)")
  r"[^]{1,100}\b(word1|...|word10)\b(?<!\b(?:\1|\2))"
  ...
  r"[^]{1,100}\b(word1|...|word10)\b(?<!\b(?:\1|\2|\3|\4|...|\9))");

对于所有这些负面的后视,这可能不会特别有效,但最大的问题是它的字数呈二次方增长。

所以,我会做的是:

List<Match>? findWords(String source, List<String> words) {
 var re = RegExp("\\b(?:${words.join("|")})\\b");
 var seenWords = <String>{};
 var matches = <Match>[];
 for (var m in re.allMatches(source)) {
   var str = m[0];
   if (seenWords.add(str)) {
     matches.add(m);
     if (matches.length == words.length) return matches;
   }
 }
 return null;
}

Match这将为参数中的每个单词返回 a words,如果它找到所有单词,如果null没有。


推荐阅读