【发布时间】:2020-04-10 05:56:35
【问题描述】:
我能否以忽略输出中的 ANSI 转义码(尤其是颜色)的方式使用 pexpect?我正在尝试这样做:
expect('foo 3 bar 5')
...但是有时我会得到带有 ANSI 彩色数字的输出。问题是我不知道哪些数字会有 ANSI 颜色,哪些没有。
有没有办法使用 pexpect 但让它忽略子进程响应中的 ANSI 序列?
【问题讨论】:
标签: pexpect ansi-escape
我能否以忽略输出中的 ANSI 转义码(尤其是颜色)的方式使用 pexpect?我正在尝试这样做:
expect('foo 3 bar 5')
...但是有时我会得到带有 ANSI 彩色数字的输出。问题是我不知道哪些数字会有 ANSI 颜色,哪些没有。
有没有办法使用 pexpect 但让它忽略子进程响应中的 ANSI 序列?
【问题讨论】:
标签: pexpect ansi-escape
此解决方法部分违背了使用 pexpect 的目的,但它满足了我的要求。
这个想法是:
expect 任何东西(正则表达式匹配 .*),然后是下一个提示(在我的例子中是 xsh $ - 注意“提示”正则表达式中的反斜杠)after 属性[1:]
with pexpect.spawn(XINU_CMD, timeout=3, encoding='utf-8') as c:
# from https://stackoverflow.com/a/14693789/5008284
ansi_escape = re.compile(r"\x1B[@-_][0-?]*[ -/]*[@-~]")
system_prompt_wildcard = r".*xsh \$ " # backslash because prompt is "xsh $ "
# tests is {command:str, responses:[str]}
for test in tests:
c.sendline(test["cmd"])
response = c.expect([system_prompt_wildcard, pexpect.EOF, pexpect.TIMEOUT]) #=> (0|1|2)
if response != 0: # any error
continue
response_text = c.after.split('\n')[1:]
for expected, actual in zip(test['responses'], response_text):
norm_a = ansi_escape.sub('', norm_input.sub('', actual.strip()))
result = re.compile(norm_a).findall(expected)
if not len(result):
print('NO MATCH FOUND')
【讨论】:
这是一个不完全令人满意的提议,将 pexpect 类 pexpect.Expecter 和 pexpect.spawn 的 2 个例程子类化,以便传入数据可以在添加到缓冲区和测试模式匹配之前删除转义序列。这是一个惰性实现,因为它假定任何转义序列总是以原子方式读取,但处理拆分读取更加困难。
# https://stackoverflow.com/a/59413525/5008284
import re, pexpect
from pexpect.expect import searcher_re
# regex for vt100 from https://stackoverflow.com/a/14693789/5008284
class MyExpecter(pexpect.Expecter):
ansi_escape = re.compile(rb'\x1B[@-_][0-?]*[ -/]*[@-~]')
def new_data(self, data):
data = self.ansi_escape.sub(b'', data)
return pexpect.Expecter.new_data(self, data)
class Myspawn(pexpect.spawn):
def expect_list(self, pattern_list, timeout=-1, searchwindowsize=-1,
async=False):
if timeout == -1:
timeout = self.timeout
exp = MyExpecter(self, searcher_re(pattern_list), searchwindowsize)
return exp.expect_loop(timeout)
这假设您使用带有列表的expect() 调用,并执行
child = Myspawn("...")
rc = child.expect(['pat1'])
由于某种原因,在解码之前我必须使用字节而不是字符串来获取数据,但这可能只是因为当前的语言环境不正确。
【讨论】: