分割转义分隔符

格拉多斯

编辑:改写问题以更好地理解。

对于我正在使用霍夫曼压缩技术进行的项目,我需要序列化霍夫曼树。

以下文字

“买票可以骑着巨大的螺旋状水滑梯,也可以穿过漆成鲜艳的胶合板制成的游乐迷宫。整个夏天,笑声不断。”

将产生一个霍夫曼树,其序列化如下所示:

'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()时,我总是会遇到两个问题之一

  1. 斜线将与管道一起删除。
  2. 斜杠将包含在列表中自己的单元格中。

两者都破坏了我的非序列化。我需要删除管道,同时忽略斜线。

如果可能,我想知道如何使用re.split()做到这一点,尽管我开始认为只有使用re.findall()才有可能

编辑说明:拆分数据不应包含空字符串。

帕特里克·莫平

我编写了一个酷刑测试,该测试创建并组合了多个小字符串-我认为它应该处理大多数极端情况。

马里亚诺的finditer()答案通过了飞跃测试。但是,在我的机器上,它比使用慢15%-20%split()

但是,他有一个新的findall()解决方案,在此方法中,他在将字符串传递给之前对其进行了修改re,该方法比split()此处显示解决方案更快,更简单

请注意,由于最近澄清了OP将在竖线字符之间永远不会有任何空字符串的情况,因此,findall()由Mariano提出的原始示例(无需对初始字符串进行修改)最适合原始张贴者。

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)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章