在预期响应中忽略ANSI颜色

时间:2019-12-17 17:21:37

标签: pexpect ansi-escape

我可以使用pexpect来忽略输出中的ANSI转义码(尤其是颜色)吗?我正在尝试这样做:

expect('foo 3 bar 5')

...但是有时我得到带有ANSI彩色数字的输出。问题是我不知道哪些数字将具有ANSI颜色,哪些将不会。

是否可以使用pexpect,但在子进程的响应中是否忽略ANSI序列?

2 个答案:

答案 0 :(得分:0)

此变通办法部分地违反了使用pexpect的目的,但它满足了我的要求。

想法是:

  1. expect的所有内容(正则表达式匹配.*)后跟下一个提示符(在我的情况下为xsh $-注意“提示”正则表达式中的反斜杠)
  2. 获取after属性
  3. 删除提示:[1:]
  4. 从中删除ANSI转义代码
  5. 将过滤后的文本与我的“预期”响应正则表达式进行比较
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')

答案 1 :(得分:0)

这是一个不完全令人满意的建议,将pexpect类的两个例程pexpect.Expecterpexpect.spawn子类化,以便传入数据可以在将其添加到缓冲区并测试模式匹配之前删除转义序列。 。这是一个懒惰的实现,因为它假定将始终以原子方式读取任何转义序列,但是应对拆分读取会更加困难。

# 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'])

出于某种原因,在解码数据之前,我不得不使用字节而不是字符串,但这可能只是由于当前不正确的语言环境造成的。