Python Regex Negative Lookbehind

时间:2015-09-21 21:14:31

标签: python regex negative-lookbehind

我有一个庞大的CT扫描结果和印象数据库。我正在尝试构建一个正则表达式,它搜索一个整数或浮点数后跟“' mm'这是与“结节”这个词相邻的。前进或后退。这是我到目前为止的正则表达式:

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

但是,我需要确保先前或之前的测量不会先发现这些结果。放射科医生参考以前的扫描。所以我正在尝试一种消极的观察,如下所示:

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

然而,我无法让它发挥作用。以下段为例。

  

&#34;例如,位于右下方的最大结节   叶片和目前的尺寸为4.4毫米(图像#82,系列3)   在09/01/2011测得3.6毫米。&#34;

在这种情况下,我希望正则表达式达到4.4毫米而不是3.6毫米。此外,如果找到多个匹配,我想只保留找到的最大尺寸。例如,

  

&#34;例如,位于右下方的最大结节   叶片和目前的尺寸为4.4毫米(图像#82,系列3)   在09/01/2011测得3.6毫米。发现另一个结节为2.2毫米。

在这种情况下,我想确保只识别4.4毫米。

真正感谢任何帮助。只是不能让这种消极的观察能够发挥作用!谢谢!

4 个答案:

答案 0 :(得分:1)

两种可能性:

1)使用lookbehinds:

(?<!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方法并获取最大的结果(正则表达式无法解决此类问题)。

答案 1 :(得分:1)

如果附近需要nodule个字词,您可以尝试使用:

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

DEMO

匹配如果:

  • 结节与mm中的值相同([^.?!\n] 应该防止它,但是像先生,小数等字样会打扰 匹配),您可以将其替换为.+?DEMO),但它可以匹配句子
  • 该值在字结节之前或之后(在此节目中,如果存在的话) 是之前的值,它将首先匹配,
  • 值将以组的形式捕获:在 - \ 1之前,在\ _2之后,
  • 它应该与g和i模式一起使用

其他类似的解决方案是:

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

DEMO

仅基于外观,它不会直接匹配文本,而是零长度位置,并将值捕获到组中。

答案 2 :(得分:1)

让我们分解,保留相关部分。到目前为止,您有两个选择:

选项1 (数字后跟&#34; nodule&#34;):

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

选项2 (&#34; nodule&#34;后跟数字):

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

您应该知道正则表达式引擎是greedy。这意味着[\s\S]{1,24}将尝试尽可能多地匹配,匹配不一定最接近&#34; nodule&#34;的数字。例如,

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

Text: ... nodule measured 1.4 mm. Another 3.2 mm ...
                                          ^    ^
                                          |    |
          matches this second occurence.  +----+

要解决此问题,请在量词后添加额外的 ? 以使其成为lazy。因此,请使用[\s\S]{0,24}

,而不是使用[\s\S]{0,24}?
  

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

这个例子有&#34; nodule&#34;相隔超过24个字符。你应该增加两者之间的字符数。也许是[\s\S]{0,70}?

  

所以我正在尝试一种负面的背后隐藏

Lookbehinds仅断言紧靠某个位置之前的文本。为了避免这种情况,我建议使用文本&#34; previously measured&#34;来消费它周围的一些字符。那么,你怎么知道不考虑这些案件呢?很容易,不要创建捕获。所以你会匹配像

这样的东西
[\s\S]{0,10}previously measured[\s\S]{0,10}

并丢弃该匹配,因为它没有返回任何组。此外,您可以在此处包含不同的例外情况:

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

如果找到多个匹配,我想只保留找到的最大尺寸

你不能用正则表达式做到这一点。在代码中循环以找到最大的。

结果:

根据这些条件,我们有:

[\s\S]{0,10}previously measured[\s\S]{0,10}|([0-4]\.\d+\s*[mM]{2})[\s\S]{0,70}?[Nn]odule|[Nn]odule[\s\S]{0,70}?([0-4]\.\d+\s*[mM]{2})

DEMO

要检查的额外条件

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

  1. 不允许在换行后匹配。
  2. 如果在&#34; nodule&#34;之间完全停止,请不要匹配。和数字。
  3. 寻找措施附近的日期。

答案 3 :(得分:1)

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

$location.path('/search/query/' + encodeURIComponent($scope.searchTerm) );

所以在这个例子中,我最终没有做一个负面的后视,而是做了一个捕捉组。

感谢大家的意见。