【问题标题】:ignore ANSI colors in pexpect response忽略预期响应中的 ANSI 颜色
【发布时间】:2020-04-10 05:56:35
【问题描述】:

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

expect('foo 3 bar 5')

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

有没有办法使用 pexpect 但让它忽略子进程响应中的 ANSI 序列?

【问题讨论】:

    标签: pexpect ansi-escape


    【解决方案1】:

    此解决方法部分违背了使用 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')
    

    【讨论】:

      【解决方案2】:

      这是一个不完全令人满意的提议,将 pexpect 类 pexpect.Expecterpexpect.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'])
      

      由于某种原因,在解码之前我必须使用字节而不是字符串来获取数据,但这可能只是因为当前的语言环境不正确。

      【讨论】:

        猜你喜欢
        • 2012-08-01
        • 2020-03-09
        • 1970-01-01
        • 2015-02-20
        • 1970-01-01
        • 2011-01-15
        • 2021-03-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多