编辑:
重新提出问题以便更好地理解.
对于我正在使用霍夫曼压缩的项目,我需要序列化我的霍夫曼树.
以下文字
“bought tickets to ride down a giant spiraling water slide or run
through a play maze made from brightly painted plywood. All summer
long, the sounds of laughing”
将产生一个霍夫曼树,其序列化将如下所示:
'N57|L23, |N34|N16|N8|N4|N2|L1,made|L1,long|N2|L1,bought' \
'|L1,summer|N4|N2|L1,painted|L1,from|N2|L1,|L1,sounds|N8|N4|N2|L1,play|' \
'L1,tickets|N2|L1,All|L1,down|N4|N2|L1,brightly|L1,spiraling|N2|L1,giant|' \
'L1,ride|N18|N8|N4|N2|L1,. |L1,plywood|N2|L1,laughingreplace|L1,water|N4|' \
'N2|L1,the|L1,to|N2|L1,of|L1,through|N10|N4|N2|L1,run|L1,or|L2,a|N6|N3|' \
'L1,slide|N2|L1,maze|L1,, |L3,'
注意:这是分隔树符号的正则表达式:
'(\W+)'
文本也可以是HTML并包含字符.
'|' and '\'
为了逃避他们,我改变了
'|' to '\|'
'\' to '\\'
拆分数据时,我需要忽略转义字符,只删除管道.鉴于下一个输入,这成为一个问题:
'replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>'
这是序列化输出
'N19|N8|N4|N2|L1,)|L1," );</|N2|L1,script|L1,client|' \
'N4|N2|L1,2|L1,js|N2|L1,(\|L1,nojs|N11|N4|L2,s|N2|L1,replace|L1,>' \
'|N7|N3|L1,1client|N2|L1,$|L1,( /(^\|\|N4|N2|L1,\|$)/, "$|L1,|L2,-'
试图拆分它现在成了一个问题.我明白我需要删除前面有偶数斜线的管道.
['\\|', '|', '\\\\|', ...] Valid delimiters
['\|', '\\\|', ...] Invalid delimiters
当我的序列化字符串在其末尾包含斜杠时会发生这种情况.
'N54, test\\' will turn into 'N54, test\\\\|N44 ...'
到目前为止,我已经到了这个正则表达式的地步
r'(?<!\\)(\\\\)*\|'
在它们之前捕获具有偶数斜线的管道.但是在使用时
re.split()我将永远有两个问题之一
>斜杠将与管道一起移除.
>斜杠将包含在列表中自己的单元格中.
两者都打破了我的反序列化.
我需要移除管道,而忽略斜线.
如果可能的话,我想知道如何用re.split()来做到这一点虽然我开始认为它只能用re.findall()
编辑
澄清:拆分数据不应该有空字符串.
解决方法:
我写了一个折磨测试,创造并组合了几个小字符串 – 我认为它应该照顾大多数角落案例.
马里亚诺的发现者()答案通过了这个测试的飞行颜色.但是,在我的机器上它比使用split()慢15%-20%.
但是,他有一个新的findall()解决方案,他在将字符串传递给re之前对其进行修改,这比此处显示的split()解决方案更快更简单.
请注意,最近澄清了OP在管道字符之间永远不会有任何空字符串,Mariano提出的原始findall()示例(不需要初始字符串修改)对于原始海报是最好的.
Mariano的新findall()解决方案带有预先修改过的字符串,对于一般情况来说可能是最好的. split()位居第二,但这是我关注的焦点,因为它是原始问题的焦点:-)
以下代码适用于Python 2和Python 3.
import re
import itertools
import time
def use_finditer(data):
regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
result = []
for m in regex.finditer(data):
result.append(m.group(1))
if (not m.group(2)):
break
return result
def use_split(data):
regex = re.compile(r'(?:\|)?((?:[^|\\]|\\.)*)')
result = regex.split(data)
start_delete = data.startswith('|') * 2 if data else 1
del result[start_delete::2]
return result
def check_split(split_func):
values = '', '', '', ' ', ' ', '|', '|', '\\', '\\\\', 'abc', 'd|ef', 'ghi\\'
values = [x.replace('\\', '\\\\').replace('|', '\\|') for x in values]
stuff = [], []
for i in range(1, 6):
srclist = list(itertools.permutations(values, i))
for src in srclist:
src = tuple(src)
dst = tuple(split_func('|'.join(src)))
stuff[dst != src].append((src, dst))
if not stuff[1]:
print("Successfully executed %d splits" % len(stuff[0]))
return
print(len(stuff[0]), len(stuff[1]))
stuff[1].sort(key=lambda x: (len(x), x))
for x, y in stuff[1][:20]:
z = '|'.join(x)
print(x, repr(z), y)
def check_loop(func, count=20):
start = time.time()
for i in range(count):
check_split(func)
print('Execution time: %0.2f' % (time.time() - start))
print('\nUsing finditer')
check_loop(use_finditer)
print('\nUsing split')
check_loop(use_split)