Python 正则表达式否定回顾
Python Regex Negative Lookbehind
我有一个很大的 CT 扫描结果和印象数据库。我正在尝试构建一个正则表达式,该正则表达式搜索整数或浮点数,后跟 'mm' ,它与前面或后面的单词 'nodule' 相邻。到目前为止,这是我的正则表达式:
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})
但是,我无法让它工作。以下面这段话为例。
"For example, the largest nodule which is located in the right lower
lobe and currently measures 4.4 mm (image #82, series 3) previously
measured 3.6 mm on 09/01/2011."
在这种情况下,我希望正则表达式命中 4.4 毫米而不是 3.6 毫米。此外,如果发现多个命中,我只想保留找到的最大尺寸。例如,
"For example, the largest nodule which is located in the right lower
lobe and currently measures 4.4 mm (image #82, series 3) previously
measured 3.6 mm on 09/01/2011. Another nodule was found measuring 2.2 mm.
在这种情况下,我想确保只识别出 4.4 毫米。
任何帮助将不胜感激。就是不能让这种消极的回顾工作!谢谢!
两种可能:
1) 使用回顾:
(?<!previously measured )(?<![0-9.])([0-9]+(?:\.[0-9]+)?) ?mm
第一个检查 "previously measured "
是否不在数字之前,第二个检查数字之前是否没有数字或点(否则点之后的 4 将匹配。请记住正则表达式engine returns 左边第一个结果)。
2) 使用捕获组:
previously measured [0-9]+(?:\.[0-9]+)? ?mm|([0-9]+(?:\.[0-9]+)?) ?mm
思路是匹配你之前想避免的。当capture group 1存在时,你就得到了一个结果。
关于最大的数,用re.findall
的方法,然后取最大的结果(正则表达式解决不了这种事情)。
如果附近需要nodule
字,可以试试:
(?:((?<!previously measured\s)\d+.\d+\s*mm)(?:[^.?!\n]*?)?nodule|nodule(?:[^.?!\n]*?((?<!previously measured\s)\d+.\d+\s*mm))?)
它将匹配如果:
- 结节与mm值在同一句话中(
[^.?!\n]
应该阻止它,但是像 Mr.、decimals 等词会干扰
匹配),你可以用 .+?
(DEMO) 替换它,但是它可以在句子之间匹配
- 值在单词nodule之前或之后(在这个排序中,如果有
是之前的值,先匹配),
- 值将分组捕获:之前 - \1,之后 - \2,
- 它应该与 g 和 i 模式一起使用
其他类似的解决方案是:
(?=((?<!previously measured\s)\d+.\d+ mm)[^.?!]+nodule)|(?=nodule[^.?!]+((?<!previously measured\s)\d+\.\d+ mm))
仅基于环视,它不会直接匹配文本而是零长度位置,并将值捕获到组中。
让我们分解一下,保留相关部分。现在你有两个选择:
选项 1(数字后跟“nodule
”):
([0-4]\.\d+\s*[mM]{2})[\s\S]{0,24}[Nn]odule
选项 2(“nodule
”后跟数字):
[Nn]odule[\s\S]{0,24}([0-4]\.\d+\s*[mM]{2})
您应该知道正则表达式引擎是 greedy。这意味着 [\s\S]{1,24}
会尽可能匹配,匹配不一定最接近“nodule
”的数字。例如,
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}?
.
For example, the largest nodule which is located in the right lower lobe and currently measures 4.4 mm
此处的示例中“nodule
”由超过 24 个字符分隔。您应该增加中间的字符数。也许 [\s\S]{0,70}?
.
So I am trying a negative lookbehind
Lookbehinds 仅断言紧接在特定位置之前的文本。为避免这种情况,我建议匹配文本“previously measured
”,并在其周围消耗一些字符。那么,您怎么知道不考虑这些情况呢?简单,不要创建捕获。所以你会匹配类似
的东西
[\s\S]{0,10}previously measured[\s\S]{0,10}
并放弃匹配,因为它没有 return 任何组。此外,您可以在此处包括不同的例外情况:
[\s\S]{0,10}(?:previously measured|previous scan|another patient|incorrectly measured)[\s\S]{0,10}
if multiple hits are found I would like to only keep the largest size found
你不能用正则表达式来做到这一点。循环您的代码以找到最大的。
结果:
有了这些条件,我们有:
[\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})
要检查的额外条件
也许,为了减少误报,以下选项之一变得有用:
- 不允许在换行符后进行匹配。
- 如果“
nodule
”和数字之间有句号,则不匹配。
- 寻找接近小节的日期。
关于这个问题,我最终使用 nltk 模块将报告标记为单个句子。适用于所有实例的最终正则表达式是:
nodule_search = "[\s\S]{0,10}(?:previously measured|compared to )[\s\S]{0,10}|(\d[\.,]\d+|\d+|\d\d[\.,]\d+)\s*[mM]{2}[\s\S]{0,40}?[Nn]odule|[Nn]odule[\s\S]{0,40}?(\d[\.,]\d+|\d+|\d\d[\.,]\d+)\s*[mM]{2}"
所以在这种情况下,我最终没有做负面回顾,而是做了一个捕获组。
感谢大家的意见。
我有一个很大的 CT 扫描结果和印象数据库。我正在尝试构建一个正则表达式,该正则表达式搜索整数或浮点数,后跟 'mm' ,它与前面或后面的单词 'nodule' 相邻。到目前为止,这是我的正则表达式:
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})
但是,我无法让它工作。以下面这段话为例。
"For example, the largest nodule which is located in the right lower lobe and currently measures 4.4 mm (image #82, series 3) previously measured 3.6 mm on 09/01/2011."
在这种情况下,我希望正则表达式命中 4.4 毫米而不是 3.6 毫米。此外,如果发现多个命中,我只想保留找到的最大尺寸。例如,
"For example, the largest nodule which is located in the right lower lobe and currently measures 4.4 mm (image #82, series 3) previously measured 3.6 mm on 09/01/2011. Another nodule was found measuring 2.2 mm.
在这种情况下,我想确保只识别出 4.4 毫米。
任何帮助将不胜感激。就是不能让这种消极的回顾工作!谢谢!
两种可能:
1) 使用回顾:
(?<!previously measured )(?<![0-9.])([0-9]+(?:\.[0-9]+)?) ?mm
第一个检查 "previously measured "
是否不在数字之前,第二个检查数字之前是否没有数字或点(否则点之后的 4 将匹配。请记住正则表达式engine returns 左边第一个结果)。
2) 使用捕获组:
previously measured [0-9]+(?:\.[0-9]+)? ?mm|([0-9]+(?:\.[0-9]+)?) ?mm
思路是匹配你之前想避免的。当capture group 1存在时,你就得到了一个结果。
关于最大的数,用re.findall
的方法,然后取最大的结果(正则表达式解决不了这种事情)。
如果附近需要nodule
字,可以试试:
(?:((?<!previously measured\s)\d+.\d+\s*mm)(?:[^.?!\n]*?)?nodule|nodule(?:[^.?!\n]*?((?<!previously measured\s)\d+.\d+\s*mm))?)
它将匹配如果:
- 结节与mm值在同一句话中(
[^.?!\n]
应该阻止它,但是像 Mr.、decimals 等词会干扰 匹配),你可以用.+?
(DEMO) 替换它,但是它可以在句子之间匹配 - 值在单词nodule之前或之后(在这个排序中,如果有 是之前的值,先匹配),
- 值将分组捕获:之前 - \1,之后 - \2,
- 它应该与 g 和 i 模式一起使用
其他类似的解决方案是:
(?=((?<!previously measured\s)\d+.\d+ mm)[^.?!]+nodule)|(?=nodule[^.?!]+((?<!previously measured\s)\d+\.\d+ mm))
仅基于环视,它不会直接匹配文本而是零长度位置,并将值捕获到组中。
让我们分解一下,保留相关部分。现在你有两个选择:
选项 1(数字后跟“nodule
”):
([0-4]\.\d+\s*[mM]{2})[\s\S]{0,24}[Nn]odule
选项 2(“nodule
”后跟数字):
[Nn]odule[\s\S]{0,24}([0-4]\.\d+\s*[mM]{2})
您应该知道正则表达式引擎是 greedy。这意味着 [\s\S]{1,24}
会尽可能匹配,匹配不一定最接近“nodule
”的数字。例如,
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}?
.
For example, the largest nodule which is located in the right lower lobe and currently measures 4.4 mm
此处的示例中“nodule
”由超过 24 个字符分隔。您应该增加中间的字符数。也许 [\s\S]{0,70}?
.
So I am trying a negative lookbehind
Lookbehinds 仅断言紧接在特定位置之前的文本。为避免这种情况,我建议匹配文本“previously measured
”,并在其周围消耗一些字符。那么,您怎么知道不考虑这些情况呢?简单,不要创建捕获。所以你会匹配类似
[\s\S]{0,10}previously measured[\s\S]{0,10}
并放弃匹配,因为它没有 return 任何组。此外,您可以在此处包括不同的例外情况:
[\s\S]{0,10}(?:previously measured|previous scan|another patient|incorrectly measured)[\s\S]{0,10}
if multiple hits are found I would like to only keep the largest size found
你不能用正则表达式来做到这一点。循环您的代码以找到最大的。
结果:
有了这些条件,我们有:
[\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})
要检查的额外条件
也许,为了减少误报,以下选项之一变得有用:
- 不允许在换行符后进行匹配。
- 如果“
nodule
”和数字之间有句号,则不匹配。 - 寻找接近小节的日期。
关于这个问题,我最终使用 nltk 模块将报告标记为单个句子。适用于所有实例的最终正则表达式是:
nodule_search = "[\s\S]{0,10}(?:previously measured|compared to )[\s\S]{0,10}|(\d[\.,]\d+|\d+|\d\d[\.,]\d+)\s*[mM]{2}[\s\S]{0,40}?[Nn]odule|[Nn]odule[\s\S]{0,40}?(\d[\.,]\d+|\d+|\d\d[\.,]\d+)\s*[mM]{2}"
所以在这种情况下,我最终没有做负面回顾,而是做了一个捕获组。
感谢大家的意见。