正则表达式绕过仅三个点
我有一个这样的字符串:
z='Certainly. I like apples... Really? By all means. Yes!'
我想要提取出 .
、?
和 !
这几个符号,但不想要 ...
这个子串,所以我想要的结果应该是:
['.', '?', '.', '!']
这是我目前的代码:
>>> re.findall('(?<!\.)[\.?!]', z)
['.', '.', '?', '.', '!']
这个正则表达式也把 ...
这个子串里的第一个点给捕获了。但是如果我运行:
>>> re.findall('(?<!\.{2})[\.?!]', z)
['.', '.', '.', '?', '.', '!']
结果和我预期的完全相反,我不明白为什么,因为我已经要求前面有两个点的时候不匹配(尝试使用量词的任意操作符 +?*{1,2}
会出错,因为向后查找需要固定宽度的模式)。
我有些误解了,因为我本来以为在向前查找中加上第二个 \.
会得到我想要的结果。
如果有任何建议和简短的解释,我会非常感激(我找不到和我问的完全一样的内容)。
2 个回答
2
还有一种可能性:
pat = re.compile(r"\.\.\.|([.?!])")
matches = filter(None, pat.findall(z))
这个方法是通过匹配字面上的 ...
字符串来实现的。在我们有机会把它放进一个捕获组之前(在“或”符号 |
的另一边),就先把这个字符串消耗掉。然后再过滤结果,去掉所有的 ''
(这是 findall
在找到一个空的捕获组时使用的)。
这个方法被一些人称为 最佳正则表达式技巧
2
你可以试试下面这个正则表达式,它使用了负向前瞻和负向后顾。
>>> import re
>>> z='Certainly. I like apples... Really? By all means. Yes!'
>>> z
'Certainly. I like apples... Really? By all means. Yes!'
>>> m = re.findall(r'(?<!\.)[.?!](?!\.)', z)
>>> m
['.', '?', '.', '!']
这个正则表达式会匹配那些前面没有点(.
)并且后面也没有点的符号,比如点(.
)、问号(?
)或者感叹号(!
)。