【问题标题】:Remove substring only at the end of string仅在字符串末尾删除子字符串
【发布时间】:2010-09-07 23:25:17
【问题描述】:

我有一堆字符串,其中一些有' rec'。仅当这些是最后 4 个字符时,我才想删除它。

也就是说我有

somestring = 'this is some string rec'

我希望它变成

somestring = 'this is some string'

解决这个问题的 Python 方法是什么?

【问题讨论】:

标签: python string


【解决方案1】:
def rchop(s, suffix):
    if suffix and s.endswith(suffix):
        return s[:-len(suffix)]
    return s

somestring = 'this is some string rec'
rchop(somestring, ' rec')  # returns 'this is some string'

【讨论】:

  • 请注意,endswith 也可以使用一组后缀来查找。如果有人使用此函数将元组作为suffix 传递,您将得到错误的结果。它将检查字符串列表,但删除字符串列表的长度,而不是匹配字符串的长度。
【解决方案2】:

因为无论如何你都必须得到len(trailing)(其中trailing 是你想要删除的字符串,如果它在尾随),我建议避免.endswith 在这种情况下会导致的轻微重复工作。当然,代码的证明是在时间上,所以,让我们做一些测量(按照受访者提出的函数命名):

import re

astring = 'this is some string rec'
trailing = ' rec'

def andrew(astring=astring, trailing=trailing):
    regex = r'(.*)%s$' % re.escape(trailing)
    return re.sub(regex, r'\1', astring)

def jack0(astring=astring, trailing=trailing):
    if astring.endswith(trailing):
        return astring[:-len(trailing)]
    return astring

def jack1(astring=astring, trailing=trailing):
    regex = r'%s$' % re.escape(trailing)
    return re.sub(regex, '', astring)

def alex(astring=astring, trailing=trailing):
    thelen = len(trailing)
    if astring[-thelen:] == trailing:
        return astring[:-thelen]
    return astring

假设我们将这个python文件命名为a.py,它在当前目录中;现在,...:

$ python2.6 -mtimeit -s'import a' 'a.andrew()'
100000 loops, best of 3: 19 usec per loop
$ python2.6 -mtimeit -s'import a' 'a.jack0()'
1000000 loops, best of 3: 0.564 usec per loop
$ python2.6 -mtimeit -s'import a' 'a.jack1()'
100000 loops, best of 3: 9.83 usec per loop
$ python2.6 -mtimeit -s'import a' 'a.alex()'
1000000 loops, best of 3: 0.479 usec per loop

如您所见,基于 RE 的解决方案“无可救药地被淘汰”(当一个人“过度解决”问题时经常发生这种情况——这可能是 RE 在 Python 社区中名声如此糟糕的原因之一!-),不过@Jack 评论中的建议比@Andrew 的原版要好得多。正如预期的那样,基于字符串的解决方案与我的endswith 相比,与@Jack 相比具有微不足道的优势(仅快15%)。所以,这两种纯字符串的想法都很好(以及简洁明了)——我更喜欢我的变体,只是因为从性格上来说,我是一个节俭的人(有人可能会说,小气;-)。 . “不浪费,不想要”!-)

【讨论】:

  • 你在import a' 'a.xxx中有什么空格?
  • @Blankman,这是一个运行 Python 的 bash 命令:设置 (-s) 是一个参数,另一个是正在计时的代码。每个都被引用,所以我不必担心它包括空格和/或特殊字符,操作系统课程。你总是在 bash 中用空格分隔参数(以及大多数其他 shell,包括 Windows 自己的 cmd.exe,所以我对你的问题感到非常惊讶!),并在 shell 命令中引用参数以在每个参数中保留空格和特殊字符也绝对不是我所说的任何 shell 的特殊、罕见或高级用法......!-)
  • 哦,我看到你已经绕过了endswith,正如我在杰克的回答中提到的那样。缓存 len 还避免了 Python(和 C 的!)可怕的调用开销。
  • 我想知道如果正则表达式只编译一次并重复使用多次会有什么表现。
【解决方案3】:

如果速度不重要,请使用正则表达式:

import re

somestring='this is some string rec'

somestring = re.sub(' rec$', '', somestring)

【讨论】:

    【解决方案4】:

    Python 3.9开始,可以使用removesuffix

    'this is some string rec'.removesuffix(' rec')
    # 'this is some string'
    

    【讨论】:

    • 作为补充,这是PEP616介绍的(和str.removeprefix
    【解决方案5】:

    这是杰克凯利及其兄弟答案的单行版本:

    def rchop(s, sub):
        return s[:-len(sub)] if s.endswith(sub) else s
    
    def lchop(s, sub):
        return s[len(sub):] if s.startswith(sub) else s
    

    【讨论】:

    • 如果 sub 是空字符串将不起作用。你错过了检查。
    【解决方案6】:

    你也可以使用正则表达式:

    from re import sub
    
    str = r"this is some string rec"
    regex = r"(.*)\srec$"
    print sub(regex, r"\1", str)
    

    【讨论】:

    • 在这里捕获组是矫枉过正的。 sub(' rec$', '', str) 工作。
    【解决方案7】:

    作为一种单线发电机加入:

    test = """somestring='this is some string rec'
    this is some string in the end word rec
    This has not the word."""
    match = 'rec'
    print('\n'.join((line[:-len(match)] if line.endswith(match) else line)
          for line in test.splitlines()))
    """ Output:
    somestring='this is some string rec'
    this is some string in the end word 
    This has not the word.
    """
    

    【讨论】:

      【解决方案8】:

      使用more_itertools,我们可以rstrip 传递谓词的字符串。

      安装

      > pip install more_itertools
      

      代码

      import more_itertools as mit
      
      
      iterable = "this is some string rec".split()
      " ".join(mit.rstrip(iterable, pred=lambda x: x in {"rec", " "}))
      # 'this is some string'
      
      " ".join(mit.rstrip(iterable, pred=lambda x: x in {"rec", " "}))
      # 'this is some string'
      

      在这里,我们传递了我们希望从末尾删除的所有尾随项​​。

      有关详细信息,另请参阅more_itertools docs

      【讨论】:

        【解决方案9】:

        @David Foster's answer 汲取灵感,我愿意

        def _remove_suffix(text, suffix):
            if text is not None and suffix is not None:
                return text[:-len(suffix)] if text.endswith(suffix) else text
            else:
                return text
        

        参考:Python string slicing

        【讨论】:

          【解决方案10】:
          
          def remove_trailing_string(content, trailing):
              """
              Strip trailing component `trailing` from `content` if it exists.
              """
              if content.endswith(trailing) and content != trailing:
                  return content[:-len(trailing)]
              return content
          

          【讨论】:

            【解决方案11】:

            使用:

            somestring.rsplit(' rec')[0]
            

            【讨论】:

            • 这并不总是有效。它将在所有出现的 `rec` 处拆分字符串并返回第一个片段。前缀 l 和 r 仅在分隔符字符串可以重叠或指定最大拆分数时有所不同。
            猜你喜欢
            • 2010-11-05
            • 2023-04-09
            • 1970-01-01
            • 2023-04-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多