【问题标题】:Identifying bad escape character with regex使用正则表达式识别错误的转义字符
【发布时间】:2020-05-01 16:19:08
【问题描述】:

假设我们有一个转义字符 \,它只允许紧跟在另一个 \ 之前。换句话说,转义字符\ 只允许转义自己:\。转义任何其他字符都被认为是不好的转义。

\foo      bad escape at position 0
\\foo     ok
\\\foo    bad escape at position 2
\\\\foo   ok
\\\\\foo  bad escape at position 4

我需要识别这些不良转义字符、它们的位置以及它们试图转义的内容。我们可以假设输入文本不包含换行符。当然,我可以遍历正确的转义组,直到找到一个错误的转义。

line = '\\\\\\'
i = 0

while i < len(line):
    curr_char = line[i]
    next_char = line[i+1] if i < len(line) - 1 else 'EOL'
    if curr_char == '\\':
        if next_char == '\\':
            i += 2
            continue
        else:
            print(f'bad escape at pos {i}: {next_char}')
            break
    else:
        i += 1

但我需要一个比这更快的解决方案,这就是为什么我想用正则表达式匹配坏转义。我的第一个 - 有点幼稚 - 方法是匹配任何反斜杠,除了反斜杠之外的任何反斜杠:\\([^\\]|$)

import re
p = re.compile(r'\\([^\\]|$)')

p.search('\\')      # [ok] matches the only backslash
p.search('\\f')     # [ok] matches the only backslash
p.search('\\\\')    # [err] matches the correctly escaped backslash
p.search('\\\\\\')  # [ok] matches the last backslash, which indeed is a bad escape

好吧,那行不通。下一个合乎逻辑的事情似乎是添加一个否定的后向表达式(?&lt;!\\) 以忽略转义的反斜杠。

import re
p = re.compile(r'(?<!\\)\\([^\\]|$)')

p.search('\\')      # [ok] matches the only backslash
p.search('\\f')     # [ok] matches the only backslash
p.search('\\\\')    # [ok] does not match anything
p.search('\\\\\\')  # [err] does not match the bad escape (last backslash)

我可以做的另一件事是使用替换并用占位符替换糟糕的转义,但这似乎相当hacky并且不是超级有效......而且,这个解决方案尖叫“必须有更好的方法!” :-)

import re

def f_sub(match):
    value = match.group()
    if value == '\\\\':
        return value
    return '\x00'


# bad escape before "with", before "bad" and at the end of the line
line = 'text\\\\line \\with \\\\\\bad escapes\\'
line = re.sub(r'(\\\\)|(\\([^\\]|$))', f_sub, line)

print(line)
'text\\\\line \x00ith \\\\\x00ad escapes\x00'

有人可以帮我解决这个问题吗? 提前非常感谢!

【问题讨论】:

  • 如果你直截了当地用另外两个字符替换所有双反斜杠,然后看看是否还剩下单行呢?
  • 其实这很有意义!我没有想到这一点。虽然我不想创建一个临时字符串,因为它必须尽可能快。
  • 我打赌一个简单的替换然后 find 可以随时击败一个相当复杂的正则表达式。 (当然,你应该计时。)

标签: python regex


【解决方案1】:

您可以将此正则表达式与环视一起使用:

(?<!\\)(?:\\{2})*(\\)(?!\\)

RegEx Demo

代码:

>>> reg = re.compile(r'(?<!\\)(?:\\{2})*(\\)(?!\\)')
>>> def badEsc(s):
...     m = reg.search(s)
...     if m:
...             print "bad escape at position " + str(m.start(1))
...     else:
...             print "ok"
...

测试:

>>> badEsc(r'\foo')
bad escape at position 0
>>> badEsc(r'\\foo')
ok
>>> badEsc(r'\\\foo')
bad escape at position 2
>>> badEsc(r'\\\\foo')
ok
>>> badEsc(r'\\\\\foo')
bad escape at position 4

【讨论】:

    猜你喜欢
    • 2015-09-18
    • 2023-02-21
    • 1970-01-01
    • 1970-01-01
    • 2020-02-05
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2015-03-23
    相关资源
    最近更新 更多