使用具有多个真值的 OR 使用正则表达式提取字符串它返回啥结果?

Posted

技术标签:

【中文标题】使用具有多个真值的 OR 使用正则表达式提取字符串它返回啥结果?【英文标题】:Extract string with regular expression using OR with multiple true values what result it returns?使用具有多个真值的 OR 使用正则表达式提取字符串它返回什么结果? 【发布时间】:2021-04-14 20:17:17 【问题描述】:

我可以解释一下 str.extract 如何在 python 中使用正则表达式。

例如,我有一些字符串

6/18/1985 Primary Care Doctor
In 1980, the patient was living in Naples and de
2008 partial thyroidectomy
2/6/96 sleep studyPain Treatment Pain Level

我使用以下代码提取字符串中的日期:

str.extract('((\d1,2[/]\d1,2[/]\d2,4)|(\d4))')

这段代码与我原来的刺痛完美配合,输出如下:

6/18/1985
1980
2008
2/6/96

但是,我的问题是,既然6/18/1985 在技术上匹配我的第二个条件(\d4) 与返回值1985,那么为什么我的代码仍然有效并返回值6/18/1985

我认为我最大的困惑来自|(or) 运算符如何在有多个真实结果的代码中工作,应该返回哪个?

有什么想法吗? 非常感谢提前

【问题讨论】:

正则表达式是贪婪的,它不会做多个重叠匹配。它与您的第一个选项匹配,因此它不会检查其他选项。你可以说你很幸运,把完整的日期组放在第一位 【参考方案1】:

考虑这个正则表达式匹配

import re
>>> re.findall('(\d1,2[/]\d1,2[/]\d2,4)|(\d4)|([P])', "6/18/1985 2234 Primary Care Doctor")
[('6/18/1985', '', ''), ('', '2234', ''), ('', '', 'P')]
    ^^^1st group^^^      ^^^2nd group^^^  ^^^3rd group^^^

从上面的匹配中我们可以看出,由于我们在正则表达式模式中指定了 3 个匹配组,所以正则表达式引擎将尝试匹配目标字符串中的每个单独的组,如果至少有一个匹配项,则返回该组是非空的。在这里,从字符串"6/18/1985 2234 Primary Care Doctor" 中,每个捕获组都能够找到至少一个非空匹配项,因此返回该组。 OR 告诉正则表达式尝试查找字符串中的每个模式以找到至少一个非空匹配项,如果是,则返回整个组。另一方面,如果我们尝试匹配这个字符串中的上述模式

>>> re.findall('(\d1,2[/]\d1,2[/]\d2,4)|(\d4)|([P])', "6/18/1985 Primary Care Doctor")
[('6/18/1985', '', ''), ('', '', 'P')]
   ^^^1st group^^^      ^^^3rd group^^^

我们可以看到我们没有得到第二个模式(\d4) 的任何匹配项,因为该模式在字符串中找不到单个非空匹配项(没有 4 个整数),因此只返回第一个匹配项第三种模式包含至少包含非空匹配的返回组。

在您的情况下,正则表达式始终能够在 pandas 的每一行字符串中找到至少一个非空匹配项,如下所示:

>>> df = pd.Series(["6/18/1985 Primary Care Doctor", "In 1980, the patient was living in Naples and de"])
>>> df.str.extract('(\d1,2[/]\d1,2[/]\d2,4)|(\d4)')
           0     1
0  6/18/1985   NaN
1        NaN  1980

您可以看到,第一个字符串中的第二个模式和第二个字符串中的第一个模式都有 NaN 值。

【讨论】:

感谢您的解释。我认为这里的关键是顺序很重要。但我对您的回答还有一个问题,如果我将订单切换到re.findall('(\d4)|(\d1,2[/]\d1,2[/]\d2,4)|([P])', "6/18/1985 Primary Care Doctor") 我将(\d4) 放到第一组,为什么我仍然没有在第一组中得到任何匹配,不应该返回 1985在第一组? 那是因为它从字符串的开头开始匹配,这样做后,您可以在start=0 本身找到与6/18/1985 匹配的第二个正则表达式模式,但(\d4) 不能(start=0 给出的前四个字符为 6/18 与您的第一个模式不匹配),要找到此模式的匹配项,您必须将您的 start 增加到 start=5 但您没有得到这样做的机会,因为从 start=0 本身的第二个模式中找到了匹配项,它只是以贪婪的方式从那里返回。 @FrankZ。 哇,太感谢你了,你的解释真的解开了我最近的很多困惑。【参考方案2】:

来自documentation:

在扫描目标字符串时,REs 之间用 '|' 分隔从左到右尝试。

【讨论】:

以上是关于使用具有多个真值的 OR 使用正则表达式提取字符串它返回啥结果?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式提取多个字符串?

如何在 Python 中使用正则表达式从同一个字符串中提取多个值?

如何使用 R 中的正则表达式提取 2 个或多个特殊字符之间的值? [复制]

多个正则表达式字符串模式(不同的字段)

python利用正则表达式提取字符串

使用正则表达式编辑具有文本和多个图像的 html 字符串