如何从python中的字符串中删除ANSI转义序列

发布于 2021-02-02 23:13:07

这是我的字符串:

'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'

我正在使用代码从SSH命令检索输出,并且我希望我的字符串仅包含'examplefile.zip'

如何删除多余的转义序列?

关注者
0
被浏览
70
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    使用正则表达式删除它们:

    import re
    
    # 7-bit C1 ANSI sequences
    ansi_escape = re.compile(r'''
        \x1B  # ESC
        (?:   # 7-bit C1 Fe (except CSI)
            [@-Z\\-_]
        |     # or [ for CSI, followed by a control sequence
            \[
            [0-?]*  # Parameter bytes
            [ -/]*  # Intermediate bytes
            [@-~]   # Final byte
        )
    ''', re.VERBOSE)
    result = ansi_escape.sub('', sometext)
    

    或者,在没有VERBOSE标志的情况下,以压缩形式:

    ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
    result = ansi_escape.sub('', sometext)
    

    演示:

    >>> import re
    >>> ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
    >>> sometext = 'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'
    >>> ansi_escape.sub('', sometext)
    'ls\r\nexamplefile.zip\r\n'
    

    上面的正则表达式涵盖所有7位ANSI C1转义序列,但不包括8位C1转义序列打开器。后者在当今的UTF-8世界中从未使用过,在UTF-8世界中,相同范围的字节具有不同的含义。

    如果你确实也需要覆盖8位代码(然后大概使用bytes值),则正则表达式将变成如下所示的字节模式:

    # 7-bit and 8-bit C1 ANSI sequences
    ansi_escape_8bit = re.compile(br'''
        (?: # either 7-bit C1, two bytes, ESC Fe (omitting CSI)
            \x1B
            [@-Z\\-_]
        |   # or a single 8-bit byte Fe (omitting CSI)
            [\x80-\x9A\x9C-\x9F]
        |   # or CSI + control codes
            (?: # 7-bit CSI, ESC [ 
                \x1B\[
            |   # 8-bit CSI, 9B
                \x9B
            )
            [0-?]*  # Parameter bytes
            [ -/]*  # Intermediate bytes
            [@-~]   # Final byte
        )
    ''', re.VERBOSE)
    result = ansi_escape_8bit.sub(b'', somebytesvalue)
    

    可以浓缩为

    # 7-bit and 8-bit C1 ANSI sequences
    ansi_escape_8bit = re.compile(
        br'(?:\x1B[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])'
    )
    result = ansi_escape_8bit.sub(b'', somebytesvalue)
    

    有关更多信息,请参见:

    • Wikipedia上的ANSI转义代码概述
    • ECMA-48标准,第5版(尤其是第5.3和5.3节)
      你提供的示例包含4个CSI(控制序列介绍者)代码(以\x1B[或ESC[开头字节标记),并且每个示例都包含一个SGR(选择图形呈现)代码,因为它们均以结尾m。这些参数;之间的参数(以分号分隔)告诉你的终端要使用哪些图形再现属性。因此,对于每个\x1B[....m序列,使用的3个代码是:

    • 0(或00在此示例中):reset,禁用所有属性

    • 1(或01在示例中):粗体
    • 31:红色(前景)

    但是,ANSI不仅仅是CSI SGR代码。仅使用CSI,你还可以控制光标,清除行或整个显示或滚动(当然,前提是终端支持此功能)。除CSI外,还有一些代码可以选择其他字体(SS2和SS3),发送“私人消息”(例如密码),与终端(DCS),操作系统(OSC)或应用程序本身(APC,这是应用程序实现将自定义控制代码搭载在通信流上),以及用于帮助定义字符串(SOS,字符串的开始,ST字符串终止符)或将所有内容重置为基本状态的其他代码(RIS)。以上正则表达式涵盖了所有这些。

    请注意,上述正则表达式仅删除ANSI C1代码,而不会删除这些代码可能正在标记的任何其他数据(例如OSC打开程序和终止ST代码之间发送的字符串)。删除这些将需要在此答案范围之外的其他工作。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看