【问题标题】:Python regex expression to remove hyphens between lowercase charactersPython正则表达式删除小写字符之间的连字符
【发布时间】:2018-05-15 04:08:42
【问题描述】:

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

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

我希望它返回:

'hyphenated Asia-Pacific 11-12'

【问题讨论】:

    标签: python regex hyphen


    【解决方案1】:

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

    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
    

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

    【讨论】:

      【解决方案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'
      

      上下文替换的主要复杂性(“查找所有被小写字母包围的连字符”)是尾随上下文(要匹配的模式后面的部分)不能包含在匹配中。如果是,将无法参加下一场领先的比赛。

      举个例子可能会更清楚。

      天真的解决方案是

      >>> 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 也可以做“lookbehinds”,其中一个模式只有在另一个模式之前才匹配。使用lookbehind和lookahead,我们可以这样写:

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

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

      有时使用这样的lookbehind 可以加快匹配速度。有时它会减慢它的速度。如果速度对您很重要,那么使用特定模式进行基准测试总是值得的。但首要任务是正确匹配。

      【讨论】:

        【解决方案3】:
        re.sub(r'([a-z])-([a-z])', r'\1\2', "hyphen-ated Asia-Pacific 11-12")
        

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

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

        【讨论】:

        • 请在解释中添加更多细节,解释哪个部分做了什么,更重要的是OP做错了什么。据我们所知,您刚刚回答了 OP 复制粘贴的作业问题。
        猜你喜欢
        • 2018-01-16
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 2016-12-31
        • 2022-10-05
        • 2017-04-20
        • 1970-01-01
        相关资源
        最近更新 更多