2015-03-30 145 views
3

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

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 

回答

6

你可以只使用分组和管:

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

Demo

1

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

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

这是要你以前写过什么重要的一个很好的机会:

  • 开始一个可选的字符模式\s?是缓慢的,因为字符串中的每个位置必须有和没有进行测试这个角色。因此,最好在最后捕获可选的空白字符并修剪字符串。 (在所有情况下,即使您决定在开始时捕获可选空白处,也需要修剪结果)
  • 查找带引号的部分的模式是错误且效率低下的(工作时),因为您使用点用一个贪婪的量词,所以如果在同一行中有两个引用部分(注意点不匹配换行符)之间的所有内容也将匹配。这是更好地使用否定字符类,不包含引号:"[^"]*"(注:这可以提高应对引号内的转义引号)
  • 模式为Jr.Sr.是假的太多,匹配一个字面.你需要逃避它。除 之外,该模式太不精确,因为它不检查之前是否有其他单词字符。它将匹配例如以“苏联”结尾的句子。或者包含“jr”的任何子字符串。或“sr。”。 (是完全严格的,你必须检查是否有空格或字符串的开始之前,但一个简单的字边界应该足够了大部分的时间)

现在如何建立你的交替:

订单可能很重要,特别是如果子模式不互相排斥。例如,如果您有子模式a+ba+,如果您编写a+|a+b所有b前面有一个a永远不会匹配,因为第一个分支在之前成功。但就你的例子而言,并没有这种问题。

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

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

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