Python 正则表达式匹配句子的一部分

Python 正则表达式匹配句子的一部分,python,regex,Python,Regex,我试图在下一个标点之前找到一个否定词后面的句子部分(例如,不,不能,不),并在该部分句子的每个单词末尾附加“_not”,例如: “我真的很喜欢火鸡,但不喜欢鸡肉加西红柿,因为我过敏”变成了一句话 “我真的很喜欢火鸡,但不喜欢鸡肉,不喜欢西红柿,因为我过敏。” 最初,我的方法是运行如下所示的正则表达式: (dont|cant|not)(.*)[!?,.] 要获得我感兴趣的句子部分,请逐字附上_NOT,然后运行str.replace(oldPartOfSentence,newPartOfSente

我试图在下一个标点之前找到一个否定词后面的句子部分(例如,不,不能,不),并在该部分句子的每个单词末尾附加“_not”,例如: “我真的很喜欢火鸡,但不喜欢鸡肉加西红柿,因为我过敏”变成了一句话 “我真的很喜欢火鸡,但不喜欢鸡肉,不喜欢西红柿,因为我过敏。”

最初,我的方法是运行如下所示的正则表达式:

(dont|cant|not)(.*)[!?,.]
要获得我感兴趣的句子部分,请逐字附上_NOT,然后运行str.replace(oldPartOfSentence,newPartOfSentence)

这几乎是可行的,但搜索并不贪婪,如果我在以后有一个标点符号,它会找到一个比它需要的句子更长的部分。此外,如果我有一个否定词,它也不支持这种情况,但它后面没有标点符号(那么它应该为从否定词到字符串末尾的每个词添加否定)

例如,在示例语句中运行regex

[('not', ' chicken with tomatoes')]
但如果我在结尾有句号,我会得到:

[('not', " chicken with tomatoes, because I'm allergic")]
我该如何解决这个问题,是否有更有效的解决方案?例如,是否有一种方法可以更新正则表达式以通过re.sub()自动在句子末尾附加“\u NOT”?

Per,只需将
*
更改为
*?
,使其不贪婪即可

您无法使用单个正则表达式AFAICT进行替换(请参见中的原因),但一组链式替换将起作用:

def add_nots(m):
    notty, following = m.groups()
    return notty + re.sub(r'(\S+)', r'\1_NOT', following)

notted = re.sub(r'(dont|cant|not)(.*?)(?=[!?,.]|$)', add_nots, original_string)
注意:我对正则表达式做了额外的修改,使用积极的前瞻断言来避免捕获终止标点符号(或行尾,这是一个更改;当notted line组件在字符串末尾结束时,仅使用非贪婪修复程序提供的原始版本将不匹配,而不是使用一个已识别的标点符号),因此标点符号/行尾不需要被
sub
替换函数捕获和复制

此外,如果您要经常这样做,并且与其他正则表达式混杂在一起,您可能希望预编译正则表达式对象,而不是依赖
re
缓存:

# One-time, up front, compile
word_finder = re.compile(r'(\S+)')
not_finder = re.compile(r'(dont|cant|not)(.*?)(?=[!?,.]|$)')

def add_nots(m):
    notty, following = m.groups()
    return notty + word_finder.sub(r'\1_NOT', following)

notted = not_finder.sub(add_nots, original_string)

*
更改为
*?
。谢谢,这解决了问题的第一部分。是否可以制作一些同时附加“\u NOT”的正则表达式对于匹配字符串中的每个单词?@Limonup:我不这么认为,不是直接的。我最初想尝试使用肯定的查找后断言,检查不相似的单词,并在不插入标点的情况下匹配紧跟其后的每个单词,但至少对于Python,查找后断言必须是固定宽度,并尝试向前搜索点击问题:搜索不处理重叠匹配,而需要省略匹配不相似词本身造成的匹配(AFAICT)也不切实际。你需要链接regex调用。我不知道有自动更新的regex。你最好匹配你需要的,然后应用你想要的。编辑:注意:
add\u nots
可以是一个内联的
lambda
,它显式地调用
m.group(1)
m.group(2)
而不是解包
m.groups()
然后使用命名的值(事实上,在测试时,我就是这样做的)。但是为了避免编写不可读的单行程序(尤其是这样,您需要查看所涉及的组件),我坚持使用一个独立定义的命名函数,该函数将流程分解为逻辑组件,并使用自文档名称。谢谢,这太完美了。