【问题标题】:Regular Expression Question - Two Negative Look behinds in the same expression正则表达式问题 - 同一个表达式中的两个否定查找
【发布时间】:2020-01-31 17:54:56
【问题描述】:

我已经解决了几个小时的以下问题。 我正在尝试构建以下 RegEx:

我希望能够从句子中提取词reduced,但如果该词前面有否定表达式,则不能。

例如

Sentences                                |Output
1. lv function is reduced                    reduced
2. lv function is not reduced                -
3. reduced lv function                       reduced
4. no evidence of reduced lv function        -

现在,我已经能够在情况 3 和 4 中使用 RegEx 函数,其中形容词在感兴趣的名词之前使用否定的外观。

但是,对于情况 1 和 2,后面的负面看法不起作用。

这是要测试的句子和当前正则表达式:

((?<!((no|not|none)(?:\D*?)))(reduced|depressed|normal)(?:\D*?))?(?:lv function|lv|systolic function|left ventricular ejection fraction)(((?:.*\bnot\b)(\D*))(reduced|depressed|normal))?

Sentences :
lv function is reduced   
lv function is not reduced 
reduced lv function
no evidence of reduced lv function   

或者这里是一个链接:regexr.com/4tc61

另外,我最终将在 R 中工作。

谢谢大家。

【问题讨论】:

  • 您在构建正则表达式时犯了一个基本错误:您正在尝试为 JS 正则表达式引擎编写正则表达式,但想在 TRE/PCRE/ICU R 正则表达式引擎中使用它。所以,即使它在网上对你有用,但最终还是对你不起作用
  • \D* 是什么意思?如果确实有数字怎么办?
  • 这个不清楚,请用准确的口头要求更新问题。目前还不清楚比赛何时会失败。
  • 您尝试编写的正则表达式类似于regex101.com/r/11mwnU/2。它相当笨拙。
  • 您好 Wiktor,您编写的 ReGex 运行良好。虽然它确实很复杂,但它似乎有效。 \D* [表示 > 0 非数字字符],在这些情况下不应该有数字。事实上,我正在为 JS 正则表达式开发这个平台(仅仅是因为它是我发现的唯一一个),但我会将它转换回 R 正则表达式。

标签: r regex nlp


【解决方案1】:

正则表达式解决方案将非常复杂,只有在您理解它的情况下才能使用它。我会尽量解释清楚。

问:如果我的lookbehinds 不支持这样的模式,我如何匹配前面没有未知长度字符串的内容?
A :匹配你不需要的,跳过匹配的文本,从匹配失败的位置继续匹配。

您可以使用支持(*SKIP)(*FAIL)(或更短的(*SKIP)(*F))构造的PCRE 正则表达式来实现。

现在,看看模式:

(?:\b(?:no|not|none)\b\D*?\b(?:reduced|depressed|normal)\b\D*?\b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b|\b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b\D*?\bnot\b\D*?\b(?:reduced|depressed|normal)\b)(*SKIP)(*F)|(?:\b(reduced|depressed|normal)\b\D*?)?\b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b(?:\D*?\b(reduced|depressed|normal)\b)?

看起来很笨拙,但让我们来看看成分:

  • (?: - 作为容器的非捕获组的开始,(*SKIP)(*F) 将应用于其中的所有替代项):
    • \b(?:no|not|none)\b\D*?\b(?:reduced|depressed|normal)\b\D*?\b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b:
      • \b(?:no|not|none)\b - 非捕获组内的任何单词作为整个单词
      • \D*? - 0+ 个非数字字符
      • \b(?:reduced|depressed|normal)\b - 非捕获组内的任何单词作为整个单词
      • \D*? - 0+ 个非数字字符
      • \b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b - 非捕获组内的任何文本作为整个单词
    • | - 或
    • \b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b\D*?\bnot\b\D*?\b(reduced|depressed|normal)\b:
      • \b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b - 非捕获组内的任何文本作为整个单词
      • \D*?\bnot\b\D*? - 0+ 非数字尽可能少,整个单词 not,0+ 非数字尽可能少
      • \b(?:reduced|depressed|normal)\b - 非捕获组内的任何文本作为整个单词
  • )(*SKIP)(*F) - 容器组的结尾,以及匹配失败的 PCRE 动词,使正则表达式引擎继续从匹配失败的位置开始搜索匹配
  • | - 或者(也就是说,现在,与我们需要的下一个替代方案真正匹配)
  • (?:\b(reduced|depressed|normal)\b\D*?)?\b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b(?:\D*?\b(reduced|depressed|normal)\b)?:
    • (?:\b(reduced|depressed|normal)\b\D*?)? - 与reduced、depressed 或normal 匹配的可选非捕获组捕获到组1(我们需要提取与该组匹配的单词!)作为整个单词然后尽可能少的任何 0+ 非数字字符
    • \b(?:lv function|lv|systolic function|left ventricular ejection fraction)\b - 非捕获组内的任何文本作为整个单词
    • (?:\D*?\b(reduced|depressed|normal)\b)? - 一个可选的非捕获组,尽可能少地匹配任何 0+ 个非数字字符,然后捕获到第 2 组 a reduced、depressed 或 normal 捕获到第 1 组 作为一个整体。

有很多重复的部分,所以在模式中使用变量是有意义的:

x <- c("lv function is reduced", "lv function is not reduced", "reduced lv function", "no evidence of reduced lv function")

cap <- "reduced|depressed|normal"
negate_prefix <- paste0("(?:\\b(?:no|not|none)\\b\\D*?\\b(?:",cap,")\\b\\D*?")
match <- "\\b(?:lv function|lv|systolic function|left ventricular ejection fraction)\\b"
regex <- paste0(negate_prefix,
   match, "|", match, "\\D*?\\bnot\\b\\D*?\\b(?:",cap,")\\b)(*SKIP)(*F)|(?:\\b(",cap,")\\b\\D*?)?",match,"(?:\\D*?\\b(",cap,")\\b)?")

所以,我们只需要捕获的子字符串。见the R demo online:

results <- regmatches(x, regexec(regex, x, perl=TRUE))
unlist(lapply(results, function(x) paste(x[-1], collapse="")))
## => [1] "reduced" ""        "reduced" "" 

【讨论】:

  • @EricYamga 有一件事我没有提到:我输入的代码只有在关键短语的一侧有reduced、depressed 或normal 时才有效。 paste 将这些组连接成一个字符串,假设只有一个组包含一些文本。如果需要处理两个组都不为空的情况,请告知。
  • 不行。它只会在一侧!再次感谢!
  • 嗨@Wiktor Stribiżew 遇到了问题。 RegEx 在大多数情况下运行良好,但对于这句话:“有轻微的同心左心室肥大。视觉估计的左心室射血分数正常为 65%。没有局部室壁运动异常。多普勒参数与收缩压降低一致功能。正则表达式与句子不匹配”。这里又是演示:regexr.com/4tt3b。提前致谢!
【解决方案2】:

如果这个例子很复杂,那么这样的事情可能会奏效吗?

library(tidyverse)
library(stringr)
df <- data.frame(sent = c("lv function is reduced",
                             "lv function is not reduced",
                             "reduced lv function",
                             "no evidence of reduced lv function"))
df <- df %>% 
  mutate(out_test = +str_detect(sent, "not|no"),
         output = ifelse(out_test == 0, "reduced", NA)) %>% 
  select(-out_test)
df
                                sent  output
1             lv function is reduced reduced
2         lv function is not reduced    <NA>
3                reduced lv function reduced
4 no evidence of reduced lv function    <NA>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 2015-07-11
    • 2017-01-16
    • 1970-01-01
    相关资源
    最近更新 更多