我想匹配一个字符串直到终端字符/序列,其中:
(',',':', '%%')
。(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),只是如果它发生在另一个反斜杠之前,它会中和它作为转义字符的效果,如果它在某些终结符之前发生,它会中和它们作为终止符的效果。
答案 0 :(得分: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
(需要后期处理),但这是我的限制。
解释最重要的部分:
(?:\\\\)+
- 推进每对反斜杠。\\(?:,|:|%)
- 推进您转义的任何字符集。[^\\,:\n]
- 一般规则,任何字符,但对本案具有特殊意义的字符。(?<![^\\]%%)
- 找到非转义的%
对时停止。\\(?:[^\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\\
答案 1 :(得分:0)
<强> OP:强>
找到一个简单的方法:枚举所有法律案例,而不是尝试匹配终结符:
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)))
这种方法对于长终止子序列是不实际的。