【问题标题】:Matching till one of alternative unescaped characters/sequences or a newline匹配直到一个替代的未转义字符/序列或换行符
【发布时间】:2013-09-11 08:48:10
【问题描述】:

我想匹配一个字符串直到一个终端字符/序列,其中:

  • 终端字符/序列不是匹配的一部分。
  • 终端字符/序列是定义的集合之一,比如(',',':', '%%')
  • 转义的终端字符/模式不充当终止符。
  • 转义的反斜杠将被使用,而不是用于转义后面的字符。
  • 字符串结尾也会终止匹配,即使前面有转义字符。
  • 换行符(LF,CR) 也可以作为终止符,即使前面有转义符。他们也不是比赛的一部分(但如果有的话,最后一个悬空逃生是)。

所以核心问题是:一些终止符序列被转义符中和,而另一些则没有。

这些是一些示例字符串及其所需的匹配结果:字符序列 将被视为原始,但我使用<newline> 表示(LF,CR)(即U+000A, U+000D 中的原始换行符)

1: xxx\,aaa,bbb --> xxx\,aaa
2: xxx\\:aaa,bbb --> xxx\\
3: xxx\\\\\,aaa\::bbb --> xxx\\\\\,aaa\: 
4: xxx%%aaa --> xxx
5: xxx\%%aaa --> xxx\%%aaa
6: xxx%\%bbb\ --> xxx%\%bbb\
7: xxx\,aaa<newline>bbb --> xxx\,aaa
8: xxx\,aaa\<newline>bbb --> xxx\,aaa\

9: x\xa\a\,bb\\,bb --> x\xa\a\,bb\\

按照这里关于 SO 的其他一些问题的风格,我设法解决了这个问题:

pat = re.compile(r'.+?(?<!\\)(\\\\)*(?=[:,\n\r]|%%|$)', re.DOTALL|re.UNICODE) 

但这并没有涵盖所有规则,它存在转义换行符和转义字符串结尾的问题。

编辑: 反斜杠可以出现在任何字符之前而不会导致不匹配(参见示例 9),只是如果它出现在另一个反斜杠之前,它将抵消其作为转义字符的效果,如果它出现在某些终止符之前,它将抵消其作为终止符的效果。

【问题讨论】:

    标签: python regex


    【解决方案1】:

    这真的很有挑战性。这是我的方法:

    import re
    
    l = ['xxx\\,aaa,bbb',
     'xxx\\\\:aaa,bbb',
     'xxx\\\\\\\\\\,aaa\\::bbb',
     'xxx%%aaa',
     'xxx\\%%aaa',
     'xxx%\\%bbb\\',
     'xxx\\,aaa\nbbb',
     'xxx\\,aaa\nbbb',
     r'x\xa\a\,bb\\,bb']
    
    for s in l:
        print('|||| {0} |||| --> {1}'.format(s, re.match(r'((?:(?:(?:\\\\)+|\\(?:,|:|%)|[^\\,:\n]|\\(?:[^\n]|$))(?<![^\\]%%))*)', s).group(0).rstrip('%')))
    

    一些问题:

    首先,我不明白你的第六弦。你怎么能有一个反斜杠作为字符串的最后一个字符?这对我来说毫无意义。

    其次,我发现很难检查一个双百分号而不逃避其中的任何一个。向后看是没用的,因为我不知道会有多少个反斜杠,也不知道向前看,因为它与它们之前的字符不匹配,所以我使用了一种解决方法,即向后看匹配第一个并使用rstrip() 将其删除。那么这不是一个纯粹的regex(需要后期处理),但这是我的极限。

    解释最重要的部分:

    1. (?:\\\\)+ -- 推进每对反斜杠。
    2. \\(?:,|:|%) -- 推进任何被转义的字符集。
    3. [^\\,:\n] -- 一般规则,任何字符,但对这种情况有特殊含义的字符。
    4. (?&lt;![^\\]%%) -- 找到一对未转义的 % 时停止。
    5. \\(?:[^\n]|$) -- 匹配后跟非特殊字符或 EOL 的反斜杠。

    我将原始字符串放在管道之间以注意换行符。可能它与您的示例中的所有可能性都不匹配,但我希望您明白这一点。前面的脚本产生:

    |||| xxx\,aaa,bbb |||| --> xxx\,aaa
    |||| xxx\\:aaa,bbb |||| --> xxx\\
    |||| xxx\\\\\,aaa\::bbb |||| --> xxx\\\\\,aaa\:
    |||| xxx%%aaa |||| --> xxx
    |||| xxx\%%aaa |||| --> xxx\%%aaa
    |||| xxx%\%bbb\ |||| --> xxx%\%bbb\
    |||| xxx\,aaa
    bbb |||| --> xxx\,aaa
    |||| xxx\,aaa
    bbb |||| --> xxx\,aaa
    |||| x\xa\a\,bb\\,bb |||| --> x\xa\a\,bb\\
    

    【讨论】:

    • re number 6:这只是一个反斜杠,假设您正在从文件中读取 - 没有看到问题。
    • @BaselShishani:但文字反斜杠也必须转义,正如您在第二个或第三个示例中所写的那样。
    • 可以与任何字符一起使用,但具有中和某些终止符或后面的反斜杠的效果。查看我的编辑 - 谢谢。
    • @BaselShishani:用你的第九个案例更新了答案。
    【解决方案2】:

    操作:

    找到了一个简单的方法:枚举所有法律案例而不是试图匹配终结符:

    import re
    
    pat = re.compile(r'([^,:\n\r%\\]|\\[^\n\r]|%(?!%)|\\(?=\n|\r|$))*', re.DOTALL)
    
    patver = re.compile(r'''(
    [^,:\n\r%\\]  | # generic: consume any non-special char
    \\[^\n\r]     | # consume any escaped char - enc '%' and backslash
    %(?!%)        | # two successive '%', no need for lookbehind because of previous term 
    \\(?=\n|\r|$) | # dangling backslash
    )*''', re.DOTALL|re.VERBOSE)
    
    l = [r'xxx\,aaa,bbb',
     r'xxx\\:aaa,bbb',
     r'xxx\\\\\,aaa\::bbb',
     r'xxx%%aaa',
     r'xxx\%%aaa',
     'xxx%\\%bbb\\',
     'xxx\\,aaa\nbbb',
     'xxx\\,aaa\\\nbbb',
     r'x\xa\a\,bb\\,bb',
     r'xxx\\%%bbb',
     r'xxx\%%%bbb',
         ]
    
    for s in l:
        print('|||| {0} |||| --> {1}'.format(s, re.match(pat, s).group(0)))
    

    这种方法不适用于长终止序列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多