我想找到一个正则表达式,它可以将段落(长字符串,无需担心换行符)分解成句子,其简单规则是 {., ?, !} 后跟一个空格,然后大写字母应该是句子的结尾(我意识到这对于现实生活来说不是一个好的规则)。
我有一些东西可以部分工作,但它并不能完全完成工作:
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 循环?
感谢您的任何建议。
最佳答案
要解决第一个问题(
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|'
是有效匹配)!
关于Python正则表达式分割但将正则表达式匹配的结束部分放回到字符串中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30084912/