我想找到一个正则表达式,可以将段落(长字符串,无需换行符)分解成句子,其简单规则是{。,?,!}中的a,后跟空白,然后是大写字母应该是句子的结尾(我意识到这不是现实生活中的好规则)。
我有部分工作,但并不能完全完成工作:
line = 'a b c FFF! D a b a a FFF. gegtat FFF. A'
matchObj = re.split(r'(.*?\sFFF[\.|\?|\!])\s[A-Z]', line)
print (matchObj)
版画
['', 'a b c FFF!', '', ' a b a a FFF. gegtat FFF.', '']
而我想得到:
['a b c FFF!', 'D a b a a FFF. gegtat FFF.']
有两个问题。
为什么结果中有空成员(''
)?
我知道为什么D
会从拆分结果中删除-这是第一次搜索的一部分。如何以不同的方式组织搜索,以便将标点符号后的大写字母放回原处,以便可以将其包含在下一个句子中?在这种情况下,如何使D在分割结果的第二个元素中出现?
我知道我可以通过某种for循环来完成此任务,只需剥离第一个结果,加回大写字母,然后再重新进行一次,但这似乎不太像Pythonic。如果正则表达式不是解决问题的办法,那么还有什么可以避免for循环的吗?
感谢您的任何建议。
python大神给出的解决方案
要解决第一个问题(split()
返回的结果中的空字符串),请使用findall()
或finditer()
:
>>> re.findall(r'(.*?\sFFF[\.|\?|\!])\s[A-Z]', line)
['a b c FFF!', ' a b a a FFF. gegtat FFF.']
您在输出中看到空字符串,因为split()
应该这样做:使用匹配的组作为定界符分割输入字符串。
对于第二个问题(输出中缺少D),请使用lookahead assertion (?=...)
:
>>> re.findall(r'(.*?\sFFF[\.|\?|\!])\s(?=[A-Z])', line)
['a b c FFF!', 'D a b a a FFF. gegtat FFF.']
先行,否定先行,后备和否定后备是四种断言,您可以用来说“仅在组后面/前面有此组,但不使用字符串才匹配该组”。
仔细阅读您的表达式,似乎您误解了[...]
运算符的语法。看来您想匹配.
,?
和!
之一。
如果是这种情况,则可以将[\.|\?|\!]
重写为[.?!]
:
>>> re.findall(r'(.*?\sFFF[.?!])\s(?=[A-Z])', line)
['a b c FFF!', 'D a b a a FFF. gegtat FFF.']
[.?!]
不仅更紧凑,而且更正确:使用[\.|\?|\!]
时,您还匹配了|
字符(因此,'a b c FFF|'
是有效的匹配项)!