【问题标题】:python regex escape characterspython 正则表达式转义字符
【发布时间】:2010-12-22 11:26:00
【问题描述】:

我们有:

>>> str
'exit\r\ndrwxr-xr-x    2 root     root            0 Jan  1  2000 
\x1b[1;34mbin\x1b[0m\r\ndrwxr-xr-x    3 root     root           
0 Jan  1  2000 \x1b[1;34mlib\x1b[0m\r\ndrwxr-xr-x   10 root     
root            0 Jan  1  1970 \x1b[1;34mlocal\x1b[0m\r\ndrwxr-xr-x    
2 root     root            0 Jan  1  2000 \x1b[1;34msbin\x1b[0m\r\ndrwxr-xr-x    
5 root     root            0 Jan  1  2000 \x1b[1;34mshare\x1b[0m\r\n# exit\r\n'

>>> print str
exit
drwxr-xr-x    2 root     root            0 Jan  1  2000 bin
drwxr-xr-x    3 root     root            0 Jan  1  2000 lib
drwxr-xr-x   10 root     root            0 Jan  1  1970 local
drwxr-xr-x    2 root     root            0 Jan  1  2000 sbin
drwxr-xr-x    5 root     root            0 Jan  1  2000 share
# exit

我想使用正则表达式摆脱所有的 '\xblah[0m' 废话。我试过了

re.sub(str, r'(\x.*m)', '')

但这并没有成功。有什么想法吗?

【问题讨论】:

    标签: python regex ansi-escape


    【解决方案1】:

    你有几个问题:

    • 您以错误的顺序将参数传递给 re.sub。应该是:

      re.sub(regexp_pattern, replacement, source_string)

    • 字符串不包含“\x”。那个“\x1b”是转义字符,是单个字符。

    • 正如 interjay 指出的那样,您想要“.*?”而不是“.*”,否则它将匹配从第一个转义到最后一个“m”的所有内容。

    对 re.sub 的正确调用是:

    print re.sub('\x1b.*?m', '', s)
    

    或者,您可以使用:

    print re.sub('\x1b[^m]*m', '', s)
    

    【讨论】:

    • @edward-loper:非常感谢,很抱歉弄错了参数。
    • 这是一个容易犯的错误;我花了一段时间才习惯 Python regexp 参数的排序方式。基本规则是第一个参数始终是正则表达式,最后一个参数是要操作的字符串。 (除了标志或计数等可选参数,它们在最后,在要操作的字符串之后。)
    【解决方案2】:

    您需要进行以下更改:

    • 转义反斜杠
    • 切换到非贪婪匹配。否则,第一个 \x 和最后一个 m 之间的所有内容都将被删除,当出现多次时,这将是一个问题。
    • 参数顺序不正确

    结果:

    re.sub(r'(\\x.*?m)', '', str)
    

    【讨论】:

    • @interjay:抱歉,弄错了,谢谢。但是,这不起作用。它没有compaints,但所有的花言巧语都还在。
    • 我没有注意到反斜杠实际上并不是反斜杠 - 请参阅 Edward 的回答,他的回答是正确的。
    【解决方案3】:

    这些是ANSI terminal codes。它们由 ESC(字节 27,在 Python 中视为\x1B)发出信号,然后是[,然后是一些; 分隔的参数,最后是一个字母来指定它是哪个命令。 (m 是颜色变化。)

    参数通常是数字,因此对于这种简单的情况,您可以通过以下方式摆脱它们:

    ansisequence= re.compile(r'\x1B\[[^A-Za-z]*[A-Za-z]')
    ansisequence.sub('', string)
    

    从技术上讲,对于某些(与颜色无关的)控制代码,它们可能是通用字符串,这使得解析很烦人。你很少遇到这些,但如果你遇到了,我猜你必须使用一些复杂的东西,比如:

    \x1B\[((\d+|"[^"]*")(;(\d+|"[^"]*"))*)?[A-Za-z]
    

    最好的办法是说服生成字符串的任何人您不是 ANSI 终端,因此它不应在其输出中包含颜色代码。

    【讨论】:

      【解决方案4】:

      尝试运行ls --color=never -l,一开始你就不会得到ANSI转义码。

      【讨论】:

        【解决方案5】:

        这是针对您的问题的 pyparsing 解决方案,其中包含针对那些讨厌的转义序列的通用解析表达式。通过使用抑制表达式转换初始字符串,这将返回一个删除了表达式的所有匹配项的字符串。

        s = \
        'exit\r\ndrwxr-xr-x    2 root     root            0 Jan  1  2000 ' \
        '\x1b[1;34mbin\x1b[0m\r\ndrwxr-xr-x    3 root     root           ' \
        '0 Jan  1  2000 \x1b[1;34mlib\x1b[0m\r\ndrwxr-xr-x   10 root     ' \
        'root            0 Jan  1  1970 \x1b[1;34mlocal\x1b[0m\r\ndrwxr-xr-x    ' \
        '2 root     root            0 Jan  1  2000 \x1b[1;34msbin\x1b[0m\r\ndrwxr-xr-x    ' \
        '5 root     root            0 Jan  1  2000 \x1b[1;34mshare\x1b[0m\r\n# exit\r\n' \
        
        from pyparsing import (Literal, Word, nums, Combine, 
            delimitedList, oneOf, alphas, Suppress)
        
        ESC = Literal('\x1b')
        integer = Word(nums)
        escapeSeq = Combine(ESC + '[' + delimitedList(integer,';') + oneOf(list(alphas)))
        
        s_prime = Suppress(escapeSeq).transformString(s)
        
        print s_prime
        

        这将打印您想要的输出,存储在s_prime

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-02-05
          • 2010-09-21
          • 2020-07-24
          相关资源
          最近更新 更多