regex 使用NEAR正则表达式和多个术语进行字符串匹配

4smxwvx5  于 2023-04-13  发布在  其他
关注(0)|答案(2)|浏览(96)

我有一个包含一些字符串的vector,如下所示:

test_strings <- c("this string referring to dummy text should be matched", 
                  "this string referring to an example of code should be matched",
                  "this string referring to texts which are kind of dumb should be matched",
                  "this string referring to an example, but with a really long gap before mentioning a word such as 'text' should not be matched")

我有两个搜索词列表:

list_a <- c("dummy", "dumb", "example", "examples")
list_b <- c("text", "texts", "script", "scripts", "code")

我想返回list_a中的字符串和list_b中的字符串的组合,这些字符串出现在彼此的10个单词内(即test_strings的元素1-3)。
基于对这个问题的有用回答:R - Searching text with NEAR regex,我能够实现'NEAR'函数,但是一旦我包含多个术语,其中一些是子字符串,我的代码就无法返回正确的匹配。
以下是我到目前为止所尝试的:

regex_string <- "\\b(?:(dum|example)\\W+(?:\\w+\\W+){0,10}?(text|script|code)|(text|script|code)\\W+(?:\\w+\\W+){0,10}?(dum|example))\\b"

test_results <- test_strings[grepl(regex_string,test_strings, ignore.case=TRUE)]

test_results

仅返回完全匹配的字符串-即“应该匹配引用代码示例的此字符串”

regex_string <- "\\b(?:(dum.*|example.*)\\W+(?:\\w+\\W+){0,10}?(text.*|script.*|code)|(text.*|script.*|code)\\W+(?:\\w+\\W+){0,10}?(dum.*|example.*))\\b"

test_results <- test_strings[grepl(regex_string,test_strings, ignore.case=TRUE)]

test_results

允许我匹配子字符串,以便返回“this string referencing to dummy text should be matched”、“this string referencing to an example of code should be matched”和“this string referencing to texts which are kind of dummy should be matched”。
然而,“这个字符串引用了一个例子,但是在提到一个单词之前有一个很长的间隙,比如'text'不应该被匹配”也被返回,我猜是因为包含“.*”在某种程度上使0-10个单词的限制无效。
有什么办法能解决这个问题吗?

kyvafyod

kyvafyod1#

你必须使用regex吗?

sapply(
  strsplit(test_strings, "[^A-Za-z]+"),
  function(st) {
    tmp <- outer(na.omit(match(list_b, st)), na.omit(match(list_a, st)), `-`)
    any(tmp > 0 & tmp <= 10)
  })
# [1]  TRUE  TRUE  TRUE FALSE

这表明test_strings的前三个元素有来自list_b的东西,从list_a的东西中出现10个单词或更少,而第四个元素没有。

yfwxisqw

yfwxisqw2#

如果你真的需要一个正则表达式,那么这个应该可以工作:

regex_string <- r"(\b(?:dum|example)\w*(?:\W+\w+){0,10}\W+(?:text\w*|script\w*|code)\b|\b(?:text\w*|script\w*|code)(?:\W+\w+){0,10}\W+(?:dum|example)\w*\b)"

.*不起作用,因为它是贪婪的,而且没有严格边界的任何东西的可变长度匹配通常不是一个好主意。
取出:

  • \b(?:dum|example)\w*-匹配以dumexample开头的任何类型的单词
  • (?:\W+\w+){0,10}\W+-匹配最多10个单词,后跟一些非单词字符
  • (?:text\w*|script\w*|code)\b-匹配一个以text/scriptcode开头的单词替代方法类似,但位置交换。就像你的尝试一样。

Demo进一步解释。
不过,使用基于文本的解决方案来完成此类任务通常更理想。

相关问题