【问题标题】:split python string on multiple string delimiters efficiently有效地在多个字符串分隔符上拆分python字符串
【发布时间】:2023-03-08 19:28:01
【问题描述】:

假设我有一个字符串,例如 "Let's split this string into many small ones" 我想将其拆分为thisintoones

使得输出看起来像这样:

["Let's split", "this string", "into many small", "ones"]

最有效的方法是什么?

【问题讨论】:

  • 不,这涉及以特定字符序列分隔
  • 我看不出有什么不同。 Python 没有只有字符类型的字符串。
  • 我看到的唯一相似之处是这两个问题都可以使用正则表达式来解决,因为这两个问题都非常具体,因此不同。但是,如果您指出某个问题给出了关于正则表达式的一般解释,而这些问题只能在给出该领域的一般概述的意义上说是相似的,仅此而已。
  • 您要求拆分具有多个分隔符的字符串。和另一个问题一样。唯一的区别是您提供了不同的字符串示例。

标签: python string split delimiter


【解决方案1】:

具有前瞻性。

>>> re.split(r'\s(?=(?:this|into|ones)\b)', "Let's split this string into many small ones")
["Let's split", 'this string', 'into many small', 'ones']

【讨论】:

  • 感谢伊格纳西奥。很好的答案我认为你能得到最有效的答案。只是稍微了解一下这里涉及的问题?
  • 如果我有一个字符串列表而不是这三个特定字符串,这将如何改变?
  • 动态生成re expr r"\s(?=(?:" + "|".join(list) + r")\b)"
  • @cmh 谢谢,你能告诉我一些可以学习一些正则表达式技能的资源吗?
  • @cHaTrU: 这样反斜杠就不需要转义了。
【解决方案2】:

通过使用re.split()

>>> re.split(r'(this|into|ones)', "Let's split this string into many small ones")
["Let's split ", 'this', ' string ', 'into', ' many small ', 'ones', '']

通过将要拆分的单词放在捕获组中,输出包括我们拆分的单词。

如果您需要删除空格,请在 re.split() 输出上使用 map(str.strip, result)

>>> map(str.strip, re.split(r'(this|into|ones)', "Let's split this string into many small ones"))
["Let's split", 'this', 'string', 'into', 'many small', 'ones', '']

如果需要,您可以使用filter(None, result) 删除任何空字符串:

>>> filter(None, map(str.strip, re.split(r'(this|into|ones)', "Let's split this string into many small ones")))
["Let's split", 'this', 'string', 'into', 'many small', 'ones']

要拆分单词但将它们附加到以下组,您需要使用前瞻断言:

>>> re.split(r'\s(?=(?:this|into|ones)\b)', "Let's split this string into many small ones")
["Let's split", 'this string', 'into many small', 'ones']

现在我们实际上是在空格上进行拆分,但在空格后面跟着一个完整的单词,thisintoones 集合中的一个。

【讨论】:

  • 感谢 Martijn,但这也将单词分开。我需要的是分裂发生在这些词的位置。
【解决方案3】:

这是一种相当懒惰的方法:

import re

def resplit(regex,s):
    current = None
    for x in regex.finditer(s):
        start = x.start()
        yield s[current:start]
        current = start
    yield s[start:]

s = "Let's split this string into many small ones"
regex = re.compile('(this|into|ones)')
print list( resplit(regex,s) )

我不确定这是否是最有效的,但它很干净。

基本上,我们只是遍历匹配,一次取 1 个。这些片段由正则表达式开始匹配的字符串 (s) 中的索引确定。我们只是将字符串切到那个点,然后将该索引保存为下一个切片的起点。


至于表现,ignacio显然赢得了这一轮:

9.1412050724  -- Me
3.09771895409  -- ignacio

代码:

import re

def resplit(regex,s):
    current = None
    for x in regex.finditer(s):
        start = x.start()
        yield s[current:start]
        current = start
    yield s[start:]


def me(regex,s):
    return list(resplit(regex,s))

def ignacio(regex,s):
    return regex.split("Let's split this string into many small ones")

s = "Let's split this string into many small ones"
regex = re.compile('(this|into|ones)')
regex2 = re.compile(r'\s(?=(?:this|into|ones)\b)')

import timeit
print timeit.timeit("me(regex,s)","from __main__ import me,regex,s")
print timeit.timeit("ignacio(regex2,s)","from __main__ import ignacio,regex2,s")

【讨论】:

  • 感谢 mgilson,它有效。你能解释一下大局吗?
  • @cHaTrU -- 我现在正在准确计时(与其他解决方案相比)。我会发布结果——即使结果对我不利:)
  • @cHaTrU -- 时间已发布。伊格纳西奥赢了,放下手:)。我仍然断言我的答案可能会填补他没有的(非常小的)利基,所以我不会删除它。
  • re 的性能高度依赖于正则表达式。像这样简单的东西应该没问题。对整个事情使用re.split 的好处是它可以在 C 代码中进行优化,而我的代码需要有 2 个 python 生成器的开销 + 一个列表构建以及一些额外的循环开销(如果您可以在 C 中对其进行优化)。
  • @cHaTrU -- 当然:'('+'|'.join(iterable_delimiters) + ')',或者如果他们可能有正则表达式特殊字符:"({0})".format("|".join( "(?:{0})".format(re.escape(x)) for x in delimiters )) -- 我可能在我的非捕获组中过火了......我是不是正则表达式大师;-)
猜你喜欢
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 2021-06-23
  • 2020-04-17
  • 2011-11-28
相关资源
最近更新 更多