Python正则表达式用于删除小写字符之间的连字符

时间:2018-05-15 04:08:42

标签: python regex hyphen

我只需要删除小写字母之间的连字符。这是我目前的表达方式:

re.sub('\[a-z]-\[a-z]', "", 'hyphen-ated Asia-Pacific 11-12')

我希望它返回:

'hyphenated Asia-Pacific 11-12'

3 个答案:

答案 0 :(得分:2)

两种方法,包括一些时间安排:

import re, timeit

def a1():
    s = re.sub(r'([a-z])-([a-z])', r'\1\2', "hyphen-ated Asia-Pacific 11-12")

def a2():
    s = re.sub(r'(?<=[a-z])-(?=[a-z])', '', "hyphen-ated Asia-Pacific 11-12")

print(timeit.timeit(a1, number = 10**5))
print(timeit.timeit(a2, number = 10**5))

产量

0.9709542730015528
0.37731508900105837

因此,在这种情况下,lookarounds可能会更快。

答案 1 :(得分:2)

TL; DR:

>>> re.sub('([a-z])-(?=[a-z])', r'\1', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'

>>> re.sub('(?<=[a-z])-(?=[a-z])', '', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'

上下文替换的主要复杂性(&#34;查找小写字母和#34所包围的所有连字符;)后跟上下文(匹配模式后面的部分)不得包含在匹配中。如果是,它将无法参加下一场领先的比赛。

一个例子可能会更清楚。

天真的解决方案是

>>> re.sub('([a-z])-([a-z])', r'\1\2', 'hyphen-ated Asia-Pacific 11-12')
'hyphenated Asia-Pacific 11-12'

与问题中的调用不同,因为它匹配连字符周围的小写字母,捕获它们以便可以将它们重新插入到结果中。在这种情况下,模式匹配的唯一子字符串为n-a,并且已正确替换为na

但是假设我们有两个连在一起的连字符,就像这样:

>>> re.sub('([a-z])-([a-z])', r'\1\2', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obliga-tory hyphenated Asia-Pacific 11-12'

a是匹配g-a的一部分,搜索在-之后的a处重新开始。所以从来没有看到过匹配的模式a-t

要解决此问题,我们可以使用lookahead assertion

>>> re.sub('([a-z])-(?=[a-z])', r'\1', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'

现在尾随上下文(连字符后面的小写字母)不是匹配的一部分,因此我们不需要在替换中重新插入它。这意味着,在将g-与结尾a匹配后,搜索将从a开始继续,下一个匹配将为a-,结尾为t

Python也可以做&#34; lookbehinds&#34;,其中模式只有在另一个模式在它之前才匹配。使用lookbehind和lookahead,我们可以写:

>>> re.sub('(?<=[a-z])-(?=[a-z])', '', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'

这也会产生正确的答案。现在我们只是匹配连字符,但坚持它之前和之后是一个小写字母。由于匹配只是连字符,因此替换字符串可以为空。

有时使用这样的后视可以加速比赛。有时会减慢速度。如果速度对你很重要,那么总是值得用特定模式做基准测试。但首要任务是使比赛正确。

答案 2 :(得分:1)

re.sub(r'([a-z])-([a-z])', r'\1\2', "hyphen-ated Asia-Pacific 11-12")

捕获连字符前后的字母,并在剥离连字符时保留它们。 \1\2表示第一个和第二个捕获的组,在这种情况下是字母。

您当前的代码与连字符周围的两个字母相匹配,并删除整个匹配项。替换时应保留字母。