与OR运算符匹配第一个规则后,Regex不会停止评估

时间:2017-08-21 15:23:05

标签: python regex

我遇到python中的正则表达式匹配问题我有一个字符串如下:

test_str = ("ICD : 12123575.007787. 098.3,\n"
    "193235.1, 132534.0, 17707.1,1777029, V40‚0, 5612356,9899\n")

我的正则表达式有两个主要组与|绑定在一起,正则表达式如下:

  regex =   r"((?<=ICD\s:\s).*\n.*)|((?<=ICD\s).*)"

让我们称呼他们(A | B)A = ((?<=ICD\s:\s).*\n.*)B = ((?<=ICD\s).*)的位置。根据{{​​3}} |的工作方式,如果匹配A,则B不会更进一步。

现在我的问题是当我使用上面提到的正则表达式test_str时。它匹配B但不匹配A。但是,如果我使用正则表达式A仅搜索(即((?<=ICD\s:\s).*\n.*),则test_string将与正则表达式A匹配。所以我的问题是,为什么A|B正则表达式与组A不匹配并停止。以下是我的python代码:

import re

regex = r"((?<=ICD\s:\s).*\n.*)|((?<=ICD\s).*)"

test_str = ("ICD : 12123575.007787. 098.3,\n"
    "193235.1, 132534.0, 17707.1,1777029, V40‚0, 5612356,9899\n")

matches = re.search(regex, test_str)
if matches:
    print ("Match was found at {start}-{end}: {match}".format(
        start = matches.start(), 
        end = matches.end(), 
        match = matches.group()))

    for groupNum in range(0, len(matches.groups())):
        groupNum = groupNum + 1

        print ("Group {groupNum} found at {start}-{end}: {group}".format(
            groupNum = groupNum, 
            start = matches.start(groupNum), 
            end = matches.end(groupNum), 
            group = matches.group(groupNum)))

输出:

Match was found at 4-29: : 12123575.007787. 098.3,
Group 1 found at -1--1: None
Group 2 found at 4-29: : 12123575.007787. 098.3,

documentation

很抱歉,如果您无法理解。我不知道为什么Group 1 found at -1--1: None不匹配。让我知道如果你了解它可能是什么原因。

1 个答案:

答案 0 :(得分:10)

之所以发生这种情况,是因为正则表达式从左到右搜索匹配,而正则表达式的右半部分先前匹配。这是因为左侧表达式具有更长的后瞻性:(?<=ICD\s:\s)需要比(?<=ICD\s)多两个字符。

test_str = "ICD : 12123575.007787. 098.3,\n"
#                 ^ left half of the regex matches here
#               ^ right half of the regex matches here

换句话说,您的正则表达式基本上类似于(?<=.{3})(?<=.)。如果您尝试re.search(r'(?<=.{3})|(?<=.)', some_text),则可以清楚地看到正则表达式的右侧首先匹配,因为它的后观更短。

您可以通过添加否定前瞻来防止正则表达式的右半部分过早匹配来解决此问题:

regex = r"((?<=ICD\s:\s).*\n.*)|((?<=ICD\s)(?!:\s).*)"
#                                          ^^^^^^^

test_str = "ICD : 12123575.007787. 098.3,\n"
#                 ^ left half of the regex matches here
#          right half of the regex matches doesn't match at all