re.split() 后尾随空字符串

Trailing empty string after re.split()

我有两个字符串,我想在其中将数字序列与其他所有内容隔离开来。

例如:

import re
s = 'abc123abc'
print(re.split('(\d+)', s))
s = 'abc123abc123'
print(re.split('(\d+)', s))

输出如下所示:

['abc', '123', 'abc']
['abc', '123', 'abc', '123', '']

请注意,在第二种情况下,尾随有一个空字符串。

显然我可以对此进行测试并在必要时将其删除,但这看起来很麻烦,我想知道是否可以改进 RE 以解决这种情况。

您可以使用 filter 而不要 return 这个空字符串,如下所示:

>>> s = 'abc123abc123'
>>> re.split('(\d+)', s)
['abc', '123', 'abc', '123', '']

>>> list(filter(None,re.split('(\d+)', s)))
['abc', '123', 'abc', '123']

感谢@chepner,您可以生成如下列表理解:

>>> [x for x in re.split('(\d+)', s) if x]
['abc', '123', 'abc', '123']

如果您有符号或其他您需要的符号 split:

>>> s = '&^%123abc123$#@123'
>>> list(filter(None,re.split('(\d+)', s)))
['&^%', '123', 'abc', '123', '$#@', '123']

为此使用正则表达式的一种简单方法是 re.findall:

def bits(s):
    return re.findall(r"(\D+|\d+)", s)

bits("abc123abc123")
# ['abc', '123', 'abc', '123']

itertools.groupby 似乎更容易、更自然。毕竟,您是基于单个条件对可迭代对象进行分块:

from itertools import groupby

def bits(s):
    return ["".join(g) for _, g in groupby(s, key=str.isdigit)]

bits("abc123abc123")
# ['abc', '123', 'abc', '123']

这与 re.split() 本身的实现有关:您无法更改它。函数拆分时,它不会检查捕获组之后的任何内容,因此它无法为您选择保留或丢弃拆分后留下的空字符串。它只是在那里分裂并将字符串的其余部分(可以为空)留给下一个循环。

如果您不想要那个空字符串,可以在将结果收集到列表中之前通过各种方式将其删除。 user1740577 就是一个例子,但我个人更喜欢列表理解,因为它更适合简单的 filter/map 操作:

parts = [part for part in re.split('(\d+)', s) if part]

我建议不要在 列表已经创建之后检查和删除元素 ,因为它涉及更多的操作和分配。