高效地使用多个字符串分隔符拆分Python字符串

3
假设我有一个字符串,如 "让我们将这个字符串分成许多小的",我想在thisintoones上进行拆分。
输出应该类似于这样:
["Let's split", "this string", "into many small", "ones"]

什么是最有效的方法来完成它?

可能是Python字符串使用多个分隔符拆分的重复问题。 - Kugel
这段代码涉及到根据特定字符序列进行分离。 - cHaTrU
我看不出有什么区别。Python没有字符类型,只有字符串。 - Kugel
我所看到的唯一相似之处是两个问题都可以使用正则表达式来解决,除此之外,两个问题都非常具体,因此不同。然而,如果你指出了一些关于正则表达式的一般性解释的问题,那么只能说它在提供领域概述方面有些相似,没有更多的相似之处。 - cHaTrU
你能用那个例子的答案来分割这个字符串吗? - cHaTrU
显示剩余2条评论
3个回答

11

具有前瞻性。

>>> 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']

谢谢Ignacio。很好的答案,我认为这是你能得到的最有效的答案。 只是对这里涉及的问题有一点点的解释吗? - cHaTrU
如果我有一个字符串列表而不是这三个特定的字符串,那么这会如何改变? - cHaTrU
1
动态生成re表达式 r"\s(?=(?:" + "|".join(list) + r")\b)" - cmh
@cmh 谢谢, 你能告诉我一些学习正则表达式技能的资源吗? - cHaTrU
@cHaTrU:这样反斜杠就不需要转义了。 - Ignacio Vazquez-Abrams

3
通过使用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,但是这样也会把单词分开。我需要的是在那些单词的位置进行拆分。 - cHaTrU

1

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

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) )

我不确定这是否是最有效的方法,但它非常简洁。

基本上,我们只需迭代匹配并逐个获取其中的一部分。这些部分由字符串 (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")

1
@cHaTrU -- 我现在正在计时(与其他解决方案进行比较)。我会发布结果的,即使它们不利于我 :) - mgilson
1
@cHaTrU -- 时间已发布。Ignacio毫无疑问获胜:)。尽管如此,我仍然坚称我的答案可能填补他没有的(非常小的)市场需求,所以我不会删除它。 - mgilson
我认为这是一个相当简单易懂的解决方案,顺便问一下正则表达式在时间方面的一般性能如何? - cHaTrU
1
re 的性能高度依赖于正则表达式。像这样简单的东西应该没问题。使用 re.split 的好处是它可以在 C 代码中进行优化,而我的代码需要具有 2 个 Python 生成器的开销 + 列表构建和额外的循环开销,如果您可以在 C 中进行优化,则几乎是免费的。 - mgilson
1
@cHaTrU -- 当然可以:'('+'|'.join(iterable_delimiters) + ')',或者如果它们可能包含正则表达式特殊字符:"({0})".format("|".join( "(?:{0})".format(re.escape(x)) for x in delimiters )) -- 我在非捕获组方面可能有些过头了...我不是一个正则表达式大师;-) - mgilson
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接