Python re.split 并将匹配组附加到拆分的右侧或左侧

Python re.split and attaching matched group to either right or left side of the split

来自这个例子:

>>> re.split('(\W)', 'foo/bar spam\neggs')
['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs']

是否有直接的方法将捕获组与拆分的右侧或左侧部分相关联?例如。使用相同的 regex/capture 组,但产生:

['foo', '/bar', ' spam', '\neggs']

或可选

['foo/', 'bar ', 'spam\n', 'eggs']

我相信您可以通过 更改 实际的正则表达式来实现它,但这不是重点(我们可以修改示例以使匹配更复杂,这样无法重复使用它们并将它们向右或向左推是一种真正的痛苦。

不幸的是,让它成为一个非捕获组似乎只是从匹配中删除相应的字符:

>>> re.split('(?:\W)', 'foo/bar spam\neggs')
['foo', 'bar', 'spam', 'eggs']

再举一个例子,考虑一下您是否有一些来自行为不当的 CSV 文件的文本。每行只有一个实际的逗号作为分隔符,但不小心有些行在其中一个字段中也有一个逗号。幸运的是,不分隔的逗号后面总是跟着 space.

csv_data = [
    'Some good data,Id 5',
    'Some bad data, like, really bad, dude,Id 6'
]

本例中的目标是将其处理成:

[['Some good data', 'Id 5'],
 ['Some bad data, like, really bad, dude', 'Id 6']]

通过使用简单的 re.split

使用map(lambda x: re.split(",(?:\S)", x), csv_data)产生

[['Some good data', 'd 5'], 
 ['Some bad data, like, really bad, dude', 'd 6']]

并使用 map(lambda x: re.split(",(\S)", x), csv_data) 产生

[['Some good data', 'I', 'd 5'],
 ['Some bad data, like, really bad, dude', 'I', 'd 6']]

那么 re.split 对这两种情况都适用的通用方法是什么?基本上我可以用函数包装的东西,比如

def my_split(regex_chars, my_strs):
    return map(lambda x: re.split(...regex_chars..., x), my_strs)

这样

my_split(r'(\W)', ['foo/bar spam\neggs']) 

my_split(r',(\S)', csv_data) 

每个 returns 上面的预期输出。

注意:看来这在 re 中是不可能的,但在 regexre 的某种混合情况下是可能的基于拆分是否为零宽度。

不,这是不可能的。我不知道有任何正则表达式引擎支持这种事情。 Splitting就是拆分:你可以保留拆分器,也可以丢弃它,但是你不能把它和拆分之间的部分混为一谈,因为分隔器和它分开的东西是不同的。

使用 regex 模块您可以相当简单地完成它,但它确实需要更改原始正则表达式:

>>> regex.split('(?=\W)', 'foo/bar spam\neggs', flags=regex.V1)
['foo', '/bar', ' spam', '\neggs']

与内置的 re 模块不同,regex 模块允许在零宽度匹配项上进行拆分,因此您可以使用先行在下一个字符匹配 \W 的位置进行拆分.

在您在编辑中添加的示例中,即使使用普通 re 也可以使用前瞻来完成,因为拆分器不是零宽度的:

>>> map(lambda x: re.split(",(?=\S)", x), csv_data)
[['Some good data', 'Id 5'],
 ['Some bad data, like, really bad, dude', 'Id 6']]

在这种情况下,您是否可以像下面这样使用基于负前瞻的正则表达式。

>>> csv_data = [
    'Some good data,Id 5',
    'Some bad data, like, really bad, dude,Id 6'
]
>>> [re.split(r',(?!\s)', i) for i in csv_data]
[['Some good data', 'Id 5'], ['Some bad data, like, really bad, dude', 'Id 6']]

,(?!\s) 匹配所有不会后跟 space 字符的逗号。根据匹配的逗号拆分将为您提供所需的输出。