如何从 python 中的字符串中删除 ANSI 转义序列
回答问题 这是一个包含我的字符串的片段。 'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m' 该字符串是从我执行的 SSH 命令返回的。我不能使用当前状态的字符串,因为它包含 ANSI 标准化的转义序列。如何以编程方式删除转义序列,以便字符串的唯一部分是 'examplefile.zip'。 Answers 用正则表达
回答问题
这是一个包含我的字符串的片段。
'ls\r\n\x1b[00m\x1b[01;31mexamplefile.zip\x1b[00m\r\n\x1b[01;31m'
该字符串是从我执行的 SSH 命令返回的。我不能使用当前状态的字符串,因为它包含 ANSI 标准化的转义序列。如何以编程方式删除转义序列,以便字符串的唯一部分是 'examplefile.zip'
。
Answers
用正则表达式删除它们:
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 世界中从未使用过,相同的字节范围具有不同的含义。
如果您确实也需要覆盖 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)
有关更多信息,请参阅:
-
ANSI 转义码概述on Wikipedia
-
ECMA-48 标准,第 5 版(尤其是第 5.3 和 5.4 节)
您给出的示例包含 4 个 CSI(控制序列引入器)代码,由\x1B[
或 ESC[
开头字节标记,每个都包含一个 SGR(选择图形再现)代码,因为它们每个都以m
结尾。这些参数之间的参数(由;
分号分隔)告诉您的终端要使用哪些图形再现属性。所以对于每个\x1B[....m
序列,使用的 3 个代码是:
-
0(或本例中的
00
):reset,禁用所有属性 -
1(或示例中的
01
):bold -
31:红色(前景)
然而,ANSI 不仅仅是 CSI SGR 代码。单独使用 CSI,您还可以控制光标、清除线条或整个显示或滚动(当然前提是终端支持)。除了 CSI,还有一些代码可以选择替代字体(SS2
和SS3
),发送“私人消息”(想想密码),与终端(DCS
)、操作系统(OSC
)或应用程序本身(APC
,一种应用程序将自定义控制代码搭载到通信流的方法),以及帮助定义字符串(SOS
、字符串开始、ST
字符串终止符)或将所有内容重置回基本状态的其他代码(RIS
)。上面的正则表达式涵盖了所有这些。
请注意,上面的正则表达式仅删除了 ANSI C1 代码,但并未删除这些代码可能标记的任何其他数据(例如在 OSC 开启程序和终止 ST 代码之间发送的字符串)。删除这些将需要超出此答案范围的额外工作。
更多推荐
所有评论(0)