Python 正则表达式:拆分为空字符串的模式匹配
Python regex: splitting on pattern match that is an empty string
使用 re
模块,我似乎无法拆分空字符串的模式匹配:
>>> re.split(r'(?<!foo)(?=bar)', 'foobarbarbazbar')
['foobarbarbazbar']
换句话说,即使找到匹配,如果是空字符串,即使re.split
也无法拆分字符串。
docs for re.split
似乎支持我的结果。
对于这种特殊情况,"workaround" 很容易找到:
>>> re.sub(r'(?<!foo)(?=bar)', 'qux', 'foobarbarbazbar').split('qux')
['foobar', 'barbaz', 'bar']
但这是一种容易出错的方法,因为那时我必须提防已经包含我要拆分的子字符串的字符串:
>>> re.sub(r'(?<!foo)(?=bar)', 'qux', 'foobarbarquxbar').split('qux')
['foobar', 'bar', '', 'bar']
有没有更好的方法来拆分与 re
模块匹配的空模式?此外,为什么 re.split
首先不允许我这样做?我知道使用正则表达式的其他拆分算法是可能的;例如,我可以使用 JavaScript 的内置 String.prototype.split()
.
来做到这一点
import regex
x="bazbarbarfoobar"
print regex.split(r"(?<!baz)(?=bar)",x,flags=regex.VERSION1)
你可以在这里使用 regex
模块。
或
(.+?(?<!foo))(?=bar|$)|(.+?foo)$
使用re.findall
.
不幸的是 split
需要非零宽度匹配,但尚未修复,因为相当多的不正确代码取决于当前行为,例如使用 [something]*
作为正则表达式。使用此类模式现在将生成 FutureWarning
和那些 never 可以拆分任何东西的模式,从 Python 3.5 开始抛出 ValueError
:
>>> re.split(r'(?<!foo)(?=bar)', 'foobarbarbazbar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/re.py", line 212, in split
return _compile(pattern, flags).split(string, maxsplit)
ValueError: split() requires a non-empty pattern match.
这个想法是,经过一段时间的警告后,可以更改行为,以便您的正则表达式再次起作用。
如果不能使用regex
模块,可以使用re.finditer()
编写自己的拆分函数:
def megasplit(pattern, string):
splits = list((m.start(), m.end()) for m in re.finditer(pattern, string))
starts = [0] + [i[1] for i in splits]
ends = [i[0] for i in splits] + [len(string)]
return [string[start:end] for start, end in zip(starts, ends)]
print(megasplit(r'(?<!foo)(?=bar)', 'foobarbarbazbar'))
print(megasplit(r'o', 'foobarbarbazbar'))
如果您确定匹配仅为零宽度,则可以使用拆分的开头来简化代码:
import re
def zerowidthsplit(pattern, string):
splits = list(m.start() for m in re.finditer(pattern, string))
starts = [0] + splits
ends = splits + [ len(string) ]
return [string[start:end] for start, end in zip(starts, ends)]
print(zerowidthsplit(r'(?<!foo)(?=bar)', 'foobarbarbazbar'))
使用 re
模块,我似乎无法拆分空字符串的模式匹配:
>>> re.split(r'(?<!foo)(?=bar)', 'foobarbarbazbar')
['foobarbarbazbar']
换句话说,即使找到匹配,如果是空字符串,即使re.split
也无法拆分字符串。
docs for re.split
似乎支持我的结果。
对于这种特殊情况,"workaround" 很容易找到:
>>> re.sub(r'(?<!foo)(?=bar)', 'qux', 'foobarbarbazbar').split('qux')
['foobar', 'barbaz', 'bar']
但这是一种容易出错的方法,因为那时我必须提防已经包含我要拆分的子字符串的字符串:
>>> re.sub(r'(?<!foo)(?=bar)', 'qux', 'foobarbarquxbar').split('qux')
['foobar', 'bar', '', 'bar']
有没有更好的方法来拆分与 re
模块匹配的空模式?此外,为什么 re.split
首先不允许我这样做?我知道使用正则表达式的其他拆分算法是可能的;例如,我可以使用 JavaScript 的内置 String.prototype.split()
.
import regex
x="bazbarbarfoobar"
print regex.split(r"(?<!baz)(?=bar)",x,flags=regex.VERSION1)
你可以在这里使用 regex
模块。
或
(.+?(?<!foo))(?=bar|$)|(.+?foo)$
使用re.findall
.
不幸的是 split
需要非零宽度匹配,但尚未修复,因为相当多的不正确代码取决于当前行为,例如使用 [something]*
作为正则表达式。使用此类模式现在将生成 FutureWarning
和那些 never 可以拆分任何东西的模式,从 Python 3.5 开始抛出 ValueError
:
>>> re.split(r'(?<!foo)(?=bar)', 'foobarbarbazbar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/re.py", line 212, in split
return _compile(pattern, flags).split(string, maxsplit)
ValueError: split() requires a non-empty pattern match.
这个想法是,经过一段时间的警告后,可以更改行为,以便您的正则表达式再次起作用。
如果不能使用regex
模块,可以使用re.finditer()
编写自己的拆分函数:
def megasplit(pattern, string):
splits = list((m.start(), m.end()) for m in re.finditer(pattern, string))
starts = [0] + [i[1] for i in splits]
ends = [i[0] for i in splits] + [len(string)]
return [string[start:end] for start, end in zip(starts, ends)]
print(megasplit(r'(?<!foo)(?=bar)', 'foobarbarbazbar'))
print(megasplit(r'o', 'foobarbarbazbar'))
如果您确定匹配仅为零宽度,则可以使用拆分的开头来简化代码:
import re
def zerowidthsplit(pattern, string):
splits = list(m.start() for m in re.finditer(pattern, string))
starts = [0] + splits
ends = splits + [ len(string) ]
return [string[start:end] for start, end in zip(starts, ends)]
print(zerowidthsplit(r'(?<!foo)(?=bar)', 'foobarbarbazbar'))