jml*_*pez 9 python regex string split
这个问题之前已被多次提出并回答过.一些例子:[1],[2].但似乎没有更普遍的东西.我正在寻找的是一种用逗号分隔字符串的方法,这些逗号不在引号或分隔符对中.例如:
s1 = 'obj<1, 2, 3>, x(4, 5), "msg, with comma"'
Run Code Online (Sandbox Code Playgroud)
应该分成三个元素的列表
['obj<1, 2, 3>', 'x(4, 5)', '"msg, with comma"']
Run Code Online (Sandbox Code Playgroud)
现在的问题是,这可能会变得更复杂,因为我们可以看到成对<>和().
s2 = 'obj<1, sub<6, 7>, 3>, x(4, y(8, 9), 5), "msg, with comma"'
Run Code Online (Sandbox Code Playgroud)
应分为:
['obj<1, sub<6, 7>, 3>', 'x(4, y(8, 9), 5)', '"msg, with comma"']
Run Code Online (Sandbox Code Playgroud)
不使用正则表达式的天真解决方案是通过查找字符来解析字符串,<(.如果找到<或者(找到了,那么我们就开始计算奇偶校验.如果奇偶校验为零,我们只能以逗号分割.举例说,我们要分开s2,我们可以开始parity = 0,当我们到达s2[3]我们遇到<这将增加平价1.当遇到奇偶只会减少>或者)当它遇到它会增加<或(.虽然奇偶校验不是0,但我们可以简单地忽略逗号而不进行任何拆分.
这里的问题是,有没有办法快速使用正则表达式?我真的在研究这个解决方案,但这似乎并没有涵盖我给出的例子.
更通用的功能是这样的:
def split_at(text, delimiter, exceptions):
"""Split text at the specified delimiter if the delimiter is not
within the exceptions"""
Run Code Online (Sandbox Code Playgroud)
一些用途是这样的:
split_at('obj<1, 2, 3>, x(4, 5), "msg, with comma"', ',', [('<', '>'), ('(', ')'), ('"', '"')]
Run Code Online (Sandbox Code Playgroud)
正则表达式是否能够处理这个或者是否有必要创建一个专门的解析器?
虽然不可能使用正则表达式,但以下简单代码将实现所需的结果:
def split_at(text, delimiter, opens='<([', closes='>)]', quotes='"\''):
result = []
buff = ""
level = 0
is_quoted = False
for char in text:
if char in delimiter and level == 0 and not is_quoted:
result.append(buff)
buff = ""
else:
buff += char
if char in opens:
level += 1
if char in closes:
level -= 1
if char in quotes:
is_quoted = not is_quoted
if not buff == "":
result.append(buff)
return result
Run Code Online (Sandbox Code Playgroud)
在解释器中运行:
>>> split_at('obj<1, 2, 3>, x(4, 5), "msg, with comma"', ',')
#=>['obj<1, 2, 3>', ' x(4, 5)', ' "msg with comma"']
Run Code Online (Sandbox Code Playgroud)
使用迭代器和生成器:
def tokenize(txt, delim=',', pairs={'"':'"', '<':'>', '(':')'}):
fst, snd = set(pairs.keys()), set(pairs.values())
it = txt.__iter__()
def loop():
from collections import defaultdict
cnt = defaultdict(int)
while True:
ch = it.__next__()
if ch == delim and not any (cnt[x] for x in snd):
return
elif ch in fst:
cnt[pairs[ch]] += 1
elif ch in snd:
cnt[ch] -= 1
yield ch
while it.__length_hint__():
yield ''.join(loop())
Run Code Online (Sandbox Code Playgroud)
和,
>>> txt = 'obj<1, sub<6, 7>, 3>,x(4, y(8, 9), 5),"msg, with comma"'
>>> [x for x in tokenize(txt)]
['obj<1, sub<6, 7>, 3>', 'x(4, y(8, 9), 5)', '"msg, with comma"']
Run Code Online (Sandbox Code Playgroud)