结合三个正则表达式

时间:2015-03-30 21:22:30

标签: python regex

有没有办法将以下三个表达式合并为一个正则表达式?

name = re.sub(r'\s?\(\w+\)', '',name) # John Smith (ii) --> John Smith
name = re.sub(r'\s?(Jr.|Sr.)$','', name, flags=re.I) # John Jr. --> John
name = re.sub(r'".+"\s?', '', name) # Dwayne "The Rock" Johnson --> Dwayne Johnson

2 个答案:

答案 0 :(得分:6)

您可以使用分组和管道:

re.sub(r'(\s?\(\w+\))|(s?(Jr.|Sr.))|(".+"\s?)', '', name)

Demo

答案 1 :(得分:1)

如果你想获得一个有效的(并且大部分时间都在工作)模式,简单地用管道分离你的模式是一个坏主意。你必须重新考虑你想对你的模式做什么,并从头开始重写它。

p = re.compile(r'["(js](?:(?<=\b[js])r\.|(?<=\()\w+\)|(?<=")[^"]*")\s*', re.I)
text = p.sub('', text).rstrip()

这是一个很好的机会,可以批评您之前所写的内容:

  • 使用可选字符\s?启动模式的速度很慢,因为必须使用和不使用此字符测试字符串中的每个位置。因此,最好在末尾捕获可选的空格并在之后修剪字符串。 (在所有情况下,即使您决定在开始时捕获可选空格,也需要修剪结果)
  • 查找引用部分的模式是错误且低效的(当它起作用时),因为你使用带有贪心量词的点,所以如果在同一行中有两个引用部分(注意点不是' t匹配换行符)之间的所有内容也将匹配。最好使用不包含引号的否定字符类:"[^"]*" (注意:这可以改进以处理引号内的转义引号)
  • Jr.Sr.的模式也是假的,以匹配您需要逃避它的文字.。除了 这种模式太不精确了,因为它之前没有检查是否有其他单词字符。它将匹配例如以“USSR”结尾的句子。或任何包含“jr”的子串。或“sr。”。 (要完全严谨,你必须检查之前是否有空格或字符串的开头,但是大部分时间都应该有一个简单的单词边界)

现在如何建立你的交替:

顺序可能很重要,特别是如果子模式不是mutualy排他性的。例如,如果你有子模式a+ba+,如果你写a+|a+bb之前的所有a将永远不会匹配,因为第一个分支以前成功了。但是对于你的例子,没有这种问题。

顺便说一句,如果你知道其中一个分支机构有更多机会成功,那就把它放在交替的第一个位置。

您知道搜索到的子字符串以以下字符之一开头:"(js。在这种情况下,为什么不用["(js]开始模式,避免测试字符串中所有位置的模式的每个分支。 然后,由于已经消耗了第一个字符,因此您只需要使用lookbehind检查每个分支中哪些字符匹配。

通过这些小改进,您可以获得更快的模式。