Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 拆分转义分隔符_Python_Regex_Serialization_Escaping_Delimiter - Fatal编程技术网

Python 拆分转义分隔符

Python 拆分转义分隔符,python,regex,serialization,escaping,delimiter,Python,Regex,Serialization,Escaping,Delimiter,编辑: 为了更好地理解,重新措辞了这个问题 对于我正在使用哈夫曼压缩的项目,我需要序列化我的哈夫曼树 下文 “买了一张沿着巨大的螺旋形滑梯或跑步的票 整个夏天,穿过一个由色彩鲜艳的胶合板制成的游戏迷宫 长长的,笑声” 将生成一个哈夫曼树,其序列化如下所示: '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|N

编辑: 为了更好地理解,重新措辞了这个问题

对于我正在使用哈夫曼压缩的项目,我需要序列化我的哈夫曼树

下文

“买了一张沿着巨大的螺旋形滑梯或跑步的票 整个夏天,穿过一个由色彩鲜艳的胶合板制成的游戏迷宫 长长的,笑声”

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

'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,'
注意:这是分隔树符号的正则表达式:

文本也可以是HTML并包含字符

'|' and '\'
为了逃避他们,我改变了主意

'|' to '\|'
'\' to '\\'
分割数据时,我需要忽略转义字符,只删除管道。鉴于下一个输入,这将成为一个问题:

'replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>'
当序列化字符串的末尾包含斜杠时,就会发生这种情况

'N54, test\\' will turn into 'N54, test\\\\|N44 ...'
到目前为止,我已经到了这个正则表达式

r'(?<!\\)(\\\\)*\|'
r'(?
编辑

澄清:拆分的数据不应该有空字符串。

我对您试图执行的操作有点困惑。您只想拆分一个由
|
字符分隔的序列化数据字符串

>>> import re
>>> data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
>>> re.split(r'\|', data)
['', '1 \\', '2 \\\\', '3 \\\\\\', '4 \\\\\\\\', '5 \\\\\\', '\\\\', '6']
说明: 我需要移除管道,同时忽略斜线

如果可能的话,我想知道如何使用re.split()实现这一点 我开始认为只有使用re.findall()才有可能

从理论上讲,简单地使用
re.split()
是不可能的,因为正如您所说,会出现以下任一情况:EDIT(在Patrick Maupin的优秀方法之后进行了澄清,如图所示)

理论上不可能将“
|
”分隔符与纯正则表达式解决方案进行匹配,以便使用Python的标准
重新打包
在该字符上拆分。正如您所说,将出现以下任一情况:

  • 斜线将随管道一起移除
  • 斜杠将包含在列表中它们自己的单元格中
  • 原因是你需要一个反向断言,在不使用匹配字符的情况下,通过奇数个转义使匹配失败

    备选方案:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    下面的列表主要关注可能与分隔符匹配的纯正则表达式解决方案。它们基于使用不同的策略生成树,或者使用不同的正则表达式风格进行解析

  • 使用后缀符号por escapes:

    '|' to '|\'
    '\' to '\\'
    
  • 使用不能作为符号一部分的分支分隔符(因此不需要转义)

  • 调用允许(如
    \K
    in或in)的正则表达式库

  • 导入并使用正则表达式控制谓词
    (*跳过)(*失败)
    (也在PCRE中实现)
  • 代码输入(lookbehind允许可变宽度子模式)
  • 解析前反转字符串,解析后反转以进行规范化
  • 定义分隔符前面的最大反斜杠数

    这将匹配除
    |
    \
    之外的任何字符,并且还将匹配后跟任何字符的反斜杠

    输出:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    


    解决方案2:

    如果您还希望包含空令牌,则需要使用捕获组并循环每个匹配。这是为了保证,如果最后一次匹配以“<代码> <代码> >结束,则将被认为是空令牌。否则,将无法区分<代码> a b b/COD>和<代码> a b b < /c> > /p> 代码:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    输出:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    


    编辑:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    上面的解决方案着重于提供一个清晰的示例,说明如何使用正则表达式解决此问题。目标字符串和结果都不会被解析。但是,正如Patrick Maupin在他的文章中所示,它们缺乏性能。这就是为什么我提供的另一个解决方案比使用
    split()的解决方案提高了约30%
    。上述解决方案的主要问题是如何处理处于前导或尾随位置的空令牌。这可以通过一个小技巧解决


    最终解决方案: 为了避免检查是否有空令牌,我们可以在
    数据
    前面加一个“
    |
    ”分隔符。因此,我们可以使用
    findall()
    模式,在每个令牌之前加一个分隔符

    代码:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    输出:

    regex = r'(?:[^|\\]+|\\.)+'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = re.findall(regex, data)
    
    print (result)
    
    ['1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    regex = re.compile(r'((?:[^|\\]+|\\.)*)([|])?')
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    result = []
    
    for m in regex.finditer(data):
        result.append(m.group(1))
        if (not m.group(2)):
            break
    
    print (result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    
    import re
    
    # the delimiter must precede each token
    regex = r'[|]((?:[^|\\]|\\.)*)'
    data = '|1 \\|2 \\\\|3 \\\\\\|4 \\\\\\\\|5 \\\\\\|\\\\|6'
    
    # the data is prefixed with a '|' before it's passed to findall()
    result = re.findall( regex, '|' + data)
    
    print(result)
    
    ['', '1 \\|2 \\\\', '3 \\\\\\|4 \\\\\\\\', '5 \\\\\\|\\\\', '6']
    

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

    Mariano的
    finditer()

    但是,他有一个新的
    findall()
    解决方案,在将字符串传递给
    re
    之前,他会修改该字符串,这比这里显示的
    split()
    解决方案更快、更简单

    注意,最近澄清了OP在管道字符之间不会有任何空字符串,Mariano提出的原始
    findall()
    示例(无需初始字符串修改)最适合原始海报

    Mariano新的
    findall()
    预修改字符串解决方案可能最适合一般情况。
    split()
    排在第二位,但这正是我所关注的,因为它是原始问题的焦点:-)

    以下代码同时适用于Python2和Python3

    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)
    

    您的预期输出是什么?这似乎更像是一个问题,您需要扩展原始输入和您想要的预期输出。我不太关心问题的解决方案,而更关心re.split的工作方式,因此标题为。我将添加我的输入和预期的输出。太好了!两个问题:(1)是否有任何理由使用
    [|]
    而不是
    \\\\
    (2)是否