Python Regex负向后看



我有一个大的CT扫描结果和印象数据库。我试图建立一个正则表达式,搜索一个整数或浮点数,后面跟着"mm",这是相邻的单词"结节"前面或后面。这是目前为止我用到的正则表达式:

nodule_4mm_size = "(?s).*?([0-4]*.*[0-9]+s*[mM]{2})[wW]{0,24}[Nn]odule|(?s)[Nn]odule[wW]{0,24}.*?([0-4]*.*[0-9]+s*[mM]{2})”

然而,我需要确保这些发现不是在先前或先前的测量之前出现的。放射科医生参考以前的扫描结果。所以我试着用消极的眼光看过去,像这样:

(?<!previously measured)?[Nn]odule[wW]{0,24}[^.d]([0-4]s*[mM]{2}|[0-3].[0-9]s*[mM]{2}|4.0+s*[mM]{2})

然而,我不能让它工作。以下面这段话为例。

"例如,最大的结节位于右下方瓣形和当前尺寸为4.4毫米(图像#82,系列3)2011年9月1日测量3.6毫米。"

在这种情况下,我希望正则表达式击中4.4 mm而不是3.6 mm。此外,如果找到多个命中,我希望只保留找到的最大大小。例如

"例如,最大的结节位于右下方瓣形和当前尺寸为4.4毫米(图像#82,系列3)2011年9月1日测量3.6毫米。另见2.2 mm结节。

在这种情况下,我想确保仅识别4.4 mm。

任何帮助都会非常感激。就是不能让这种消极的眼神起作用!谢谢!

我们把它分解一下,保留相关的部分。到目前为止,您有两个选项:

选项1 (其次是"nodule"):

([0-4].d+s*[mM]{2})[sS]{0,24}[Nn]odule

选项2 ("nodule"其次是数量):

[Nn]odule[sS]{0,24}([0-4].d+s*[mM]{2})

你应该知道正则表达式引擎是贪婪的。这意味着[sS]{1,24}将尽可能地匹配,匹配不一定最接近"nodule"的数字。例如,

Pattern: [Nn]odule[sS]{0,24}([0-4].d+s*[mM]{2})
Text: ... nodule measured 1.4 mm. Another 3.2 mm ...
                                          ^    ^
                                          |    |
          matches this second occurence.  +----+

要解决这个问题,在量词后添加一个额外的 ? 以使其懒惰。所以,用[sS]{0,24}?代替[sS]{0,24}


例如,最大的结节位于右下叶,目前尺寸为4.4 mm

这个例子的" nodule "被超过24个字符隔开。你应该增加中间的字符数。可能是[sS]{0,70}?


所以我试着用消极的眼光看待

lookbehind只断言紧邻某个位置之前的文本。为了避免它,我建议匹配文本"previously measured",消耗它周围的一些字符。那么,你怎么知道不去考虑这些情况呢?简单,不要制造捕获。所以你会匹配像

这样的东西
[sS]{0,10}previously measured[sS]{0,10}

并丢弃匹配,因为它没有返回任何组。此外,您可以在这里包含不同的异常:

[sS]{0,10}(?:previously measured|previous scan|another patient|incorrectly measured)[sS]{0,10}

如果找到多个匹配项,我希望只保留找到的最大的

你不能用regex这样做。在代码中循环查找最大的。


结果:

有了这些条件,我们有:
[sS]{0,10}previously measured[sS]{0,10}|([0-4].d+s*[mM]{2})[sS]{0,70}?[Nn]odule|[Nn]odule[sS]{0,70}?([0-4].d+s*[mM]{2})

演示

检查

的额外条件

也许,为了减少误报,以下选项之一会变得有用:

  1. 不允许在换行符后匹配
  2. 如果在"nodule"和数字之间有一个句号,则不匹配。
  3. 查找接近测量的日期。

两种可能性:

(?<!previously measured )(?<![0-9.])([0-9]+(?:.[0-9]+)?) ?mm

第一次检查"previously measured "是否不在数字前面,第二次检查数字前面是否没有数字或点(否则点后面的4将匹配)。请记住,正则表达式引擎返回左边的第一个结果。

2)使用捕获组:

previously measured [0-9]+(?:.[0-9]+)? ?mm|([0-9]+(?:.[0-9]+)?) ?mm

这个想法是匹配你之前想要避免的。当捕获组1存在时,您就得到了一个结果。

关于最大的数,使用re.findall方法,取之后最大的结果(regex不能解决这种事情)。

如果附近需要nodule字,您可以尝试:

(?:((?<!previously measureds)d+.d+s*mm)(?:[^.?!n]*?)?nodule|nodule(?:[^.?!n]*?((?<!previously measureds)d+.d+s*mm))?)

演示

它将匹配:

  • 该结节与以mm为单位的值在同一句中([^.?!n]应该防止它,然而像先生、小数点等字会打扰match),你可以用.+? (DEMO)替换它,但是它可以在句子之间进行匹配
  • 值在字模块之前或之后(如果有,按此顺序)
  • 值将按组捕获:在- 1之前,在- 2之后,
  • 它应该与g和i模式一起使用

其他类似的解决方案是:

(?=((?<!previously measureds)d+.d+ mm)[^.?!]+nodule)|(?=nodule[^.?!]+((?<!previously measureds)d+.d+ mm))

演示

仅基于遍历,它将不直接匹配文本,而是匹配零长度位置,并将值捕获为组。

关于这个问题,我最终使用nltk模块将报告标记为单独的句子。最后一个适用于所有实例的正则表达式是:

nodule_search = "[sS]{0,10}(?:previously measured|compared to )[sS]{0,10}|(d[.,]d+|d+|dd[.,]d+)s*[mM]{2}[sS]{0,40}?[Nn]odule|[Nn]odule[sS]{0,40}?(d[.,]d+|d+|dd[.,]d+)s*[mM]{2}"

所以在这个例子中,我最终没有做一个负向后看,而是做了一个捕获组。

感谢大家的意见。

最新更新