【问题标题】:What is the best way to get rid of common substring prefix in Python3?在 Python3 中摆脱常见子字符串前缀的最佳方法是什么?
【发布时间】:2018-06-26 11:37:03
【问题描述】:

假设我们有一个字符串和一个字符串列表:

字符串:

  • str1 = <common-part>

字符串列表:

[<common-part>-<random-text-a>, <common-part>-<random-text-b>]

什么是最好的(在可读性和代码纯度的情况下)获得这样一个列表:

[<random-text-a>, <random-text-b>]

【问题讨论】:

  • 切片...替换它...正则表达式提取...尝试过任何东西,无论外观如何?
  • 您似乎希望我们为您编写一些代码。虽然许多用户愿意为陷入困境的程序员编写代码,但他们通常只会在发布者已经尝试自己解决问题时提供帮助。展示这项工作的一个好方法是包含您迄今为止编写的代码、示例输入(如果有的话)、预期输出以及您实际获得的输出(控制台输出、回溯等)。您提供的详细信息越多,您可能收到的答案就越多。检查FAQHow to Ask
  • @MooingRawr 实际上,不是。有很多解决方案,例如regexp 替换或使用len() 函数并剪切字符串的开头。这就是我发布通知的原因以防可读性和代码纯度
  • @KamilZabielski 你的评论与我要求展示你迄今为止所做的尝试有什么关系?

标签: python string python-3.x substring


【解决方案1】:

我将使用os.path.commonprefix 计算所有字符串的公共前缀,然后对字符串进行切片以删除该前缀(此函数在os.path 模块中,但不检查路径分隔符,它可用于通用上下文):

import os

p = ["<common-part>-<some-text-a>", "<common-part>-<random-text-b>"]
commonprefix = os.path.commonprefix(p)

new_p = [x[len(commonprefix):] for x in p]

print(new_p)

结果(因为commonprefix""&lt;common-part&gt;-&lt;"):

['some-text-a>', 'random-text-b>']

注释:

  • 此方法允许使用预先未知的完整动态前缀。通过反转字符串,还可以删除公共后缀。
  • 最好使用len 来分割结果而不是str.replace():它更快,而且它只删除字符串的开头,而且安全,因为我们知道所有字符串都以这个前缀。

【讨论】:

  • 有没有和len()不同的方式?
  • len()str.replace 快得多
  • 这里的分隔符不重要?文档说它仅适用于路径字符串
  • 不,它稍微滥用了这个工具,但它不关心路径分隔符等。使用该工具计算公共目录时,您必须删除最后一个分隔符之后的内容,以防所有文件以相同的前缀开头!当然可以重新编码。但在那种情况下,我不会回答。
  • @Jean-FrançoisFabre 更快 从性能的角度来看?
【解决方案2】:
MyList = ["xxx-56", "xxx-57", "xxx-58"]
MyList = [x[len(prefix):] for x in MyList] # for each x in the list, 
                                 # this function will return x[len(prefix):] 
                                 # which is the string x minus the length of the prefix string

print(MyList)

---> ['56', '57', '58']

【讨论】:

  • 我在考虑使用len(),但我在想有什么更清晰的解决方案。
  • @Kamil, len(prefix) 是一个完美的解决方案,如果字符串中的值包含两次前缀
  • 最好编码len(prefix),而不是像那样硬编码(4)。
【解决方案3】:

我会做的......

common = "Hello_"
lines = ["Hello_1 !", "Hello_2 !", "Hello_3 !"]

new_lines = []
for line in lines:
    # Finding first occurrence of the word we want to remove.
    startIndex = line.find(common) + len(common)
    new_lines.append(line[startIndex:])

print new_lines

我们只是在测试 Jean-François Fabre 的性能:

from timeit import timeit
import os

def test_fabre(lines):
    # import os

    commonprefix = os.path.commonprefix(lines)
    return [x[len(commonprefix):] for x in lines]

def test_insert(common, lines):
    new_lines = []
    for line in lines:
        startIndex = line.find(common) + len(common)
        new_lines.append(line[startIndex:])
    return new_lines

print timeit("test_insert(common, lines)", 'from __main__ import test_insert; common="Hello_";lines = ["Hello_1 !", "Hello_2 !", "Hello_3 !"]')
print timeit("test_fabre(lines)", 'from __main__ import test_fabre; lines = ["Hello_1 !", "Hello_2 !", "Hello_3 !"]')

# test_insert outputs : 2.92963575145
# test_fabre outputs : 4.23027790484 (with import os OUTside func)
# test_fabre outputs : 5.86552750264 (with import os INside func)

【讨论】:

  • 请注意,您的解决方案会删除该词以及它的 before 内容。好吧,也许之前什么都没有。
  • 你说得对,这是我没有想到的副作用。考虑一下,考虑到我写的内容,只有 len 就足够了。当我在电脑后面时,我会更新答案。 :) 谢谢
【解决方案4】:

您可以使用非常 Pythonic 的列表推导:

[newstr.replace(str1, '', 1) for newstr in list_of_strings]

newstr.replace(str, '', 1) 只会替换 str1 的第一次出现。 感谢@ev-kounis 的建议

【讨论】:

  • 字符串替换为空的就足够了。谢谢。当且仅当&lt;common-part&gt; 对列表的每个元素都是唯一的时,它才是正确的,但在这种情况下它实际上是。
  • 顺便说一下,公共部分后面会留下连字符
  • 我也相信这里的连字符会包含在公共部分中。
  • 也许可以,但是如果str1 在字符串中存在两次呢?
  • newstr.replace(str1, '', 1) 将解决@KamilZabielski 所指的问题。注意那里的1。这告诉 Python 只替换 1st 实例only
【解决方案5】:
str1 = "hello"
list1 = ["hello1", "hello2", "hello3"]
list2 = []
for i in list1:
    list2.append(i.replace(str1,""))
print list2

这是最简单的方法。

【讨论】:

  • 这项工作是否应该在hellohello 上仅返回hello
  • @cricket_007 它将起作用并给出 [''] 问题,我们必须删除 str1 没有提到它应该发生多少时间。
  • 这个问题确实要求只替换一个公共前缀
  • 基本上不清楚,因为用户没有详细解释这个东西是删除一次还是多次,但他的例子显示了一次。所以基本上我们不能说像一次或多次。
  • 我并不是说这是错误的,只是指出了边缘情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2016-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多