Python 中的正则表达式中的后视断言和负后视断言被打结了

Tied up in knots with lookbehind and negative lookbehind assertions in regular expressions in Python

我有一个 Pandas 数据框,其中有一列字符串数据由正斜杠分隔的两个不同部分组成。我想从字符串的 'right hand side' 中提取文本模式,但如果存在特定的字符串模式则不会。下面这个简单的例子说明了这个问题。

import numpy as np
import pandas as pd
import re

myDF = pd.DataFrame({'pet':['rabbit','mammal/rabbit','mammal/small fluffy rabbit','mammal/lop-eared rabbit','mammal/many rabbits','mammal/jack rabbit']})

因此,数据框如下所示:

                          pet
0                      rabbit
1               mammal/rabbit
2  mammal/small fluffy rabbit
3     mammal/lop-eared rabbit
4         mammal/many rabbits
5          mammal/jack rabbit

我希望能够提取与兔子相关的术语,但前提是它们出现在 / 分隔符的右侧,而不是 rabbit 前面有 jack(有或没有干预 space)。

我想出的正则表达式是:

rxStr = '(?P<bunny>(?<=/)(?<!jack)(?:.*rabbits?))'

...我希望任何匹配都以 / 开头,但如果以 jack 开头则不需要。但是,它并没有像我希望的那样工作。我尝试了很多变体,但都没有成功。

rxStr = '(?P<bunny>(?<=/)(?<!jack)(?:.*rabbits?))'

rx = re.compile(rxStr,flags=re.I|re.X)

rabbitDF = myDF['pet'].str.extract(rx,expand=True)

myDF = myDF.join(rabbitDF)

print(myDF)

                          pet                bunny
0                      rabbit                  NaN
1               mammal/rabbit               rabbit
2  mammal/small fluffy rabbit  small fluffy rabbit
3     mammal/lop-eared rabbit     lop-eared rabbit
4         mammal/many rabbits         many rabbits
5          mammal/jack rabbit          jack rabbit

在第 0 行中,正则表达式无法正确找到匹配项,因为没有 / 字符。但是,在第 5 行中,尽管 jack 位于 rabbit.

之前,但 jack rabbit 还是匹配的

我如何编写一个正则表达式来识别 rabbit 个术语,但前提是前面有 / 而不是前面有 jack?对于上面给出的正则表达式为何失败的任何解释,我们也将不胜感激。

使用前瞻而不是后视:

myDF.pet.str.extract('(?P<bunny>(?<=/)(?!jack).*rabbit)', expand=True)

                 bunny
0                  NaN
1               rabbit
2  small fluffy rabbit
3     lop-eared rabbit
4          many rabbit
5                  NaN

(               # capture group
    (?<=/)      # lookbehind - forwardslash
    (?!jack)    # negative lookahead - "jack" 
    .*          # match anything
    rabbit      # match "rabbit"
)

这里,否定前瞻意味着 fwslash 后面不能跟 "jack"。

In [52]:  myDF['pet'].str.extract(r'/(?P<bunny>(?!jack).*rabbits?.*)',expand=True)
Out[52]:
                 bunny
0                  NaN
1               rabbit
2  small fluffy rabbit
3     lop-eared rabbit
4         many rabbits
5                  NaN

RegEx explained ...