2015-10-16 33 views
1

我试图找到一个句子的一部分,在否定词后面出现(例如,不要,不能,不),直到下一个标点符号并在句尾附加“_NOT”例如: “我真的很喜欢土耳其,但不是西红柿鸡,因为我过敏”变成 “我真的很喜欢土耳其,但没有chicken_NOT with_NOT tomatoes_NOT,因为我过敏” 。正则表达式匹配部分句子

最初我的方法是运行正则表达式,看起来是这样的:

(dont|cant|not)(.*)[!?,.] 

让我感兴趣的句子的一部分,然后通过字去字,并附_NOT,然后运行str.replace(oldPartOfSentence,newPartOfSentence)

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

例如运行正则表达式的例句给

[('not', ' chicken with tomatoes')] 

但如果我有句号结尾,我得到:

[('not', " chicken with tomatoes, because I'm allergic")] 

我该如何解决这个问题,并在那里这是一个更有效的解决方案吗?例如,有没有办法更新正则表达式,通过re.sub()自动附加句子末尾的“_NOT”?

+4

变化'* '到'。*?'。 –

+0

谢谢,这解决了问题的第一部分。是否有可能使一些正则表达式也为匹配字符串中的每个单词添加“_NOT”? – Limon

+1

@Limonup:我不这么认为,不是直接。我最初认为尝试使用积极的背后的断言,检查不类似的单词,并匹配在每个单词跟随它没有干预标点符号,但至少对于Python来说,后面的断言必须固定宽度,并尝试向前搜索命中与不处理重叠匹配的搜索相关的问题,而需要省略匹配不相似的词本身使得(AFAICT)也不切实际。你需要链接正则表达式调用。 – ShadowRanger

回答

1

根据Steven's comment,只需将.*更改为.*?即可使其非贪婪。

你不能做替换用单一的正则表达式AFAICT(见my comment on the question的原因),但链式组替代将工作:

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行组件结束于字符串,而不是其中一个识别的标点符号),所以标点符号/行尾不需要被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) 
+0

注意:'add_nots' _could_是一个内联'lambda',显式调用'm.group(1)'和'm.group(2)',而不是解压'm.groups()',然后使用命名的值(实际上,在测试时,这就是我的做法)。但为了不写不可读的单行(特别是因为这是SO,并且需要查看涉及的组件),我坚持使用独立定义的命名函数,该函数将流分解为逻辑组件,记录名字。 – ShadowRanger

+0

谢谢,这是完美的。 – Limon