【问题标题】:readline confused by ANSI escape sequencesreadline 被 ANSI 转义序列混淆
【发布时间】:2018-11-01 09:56:06
【问题描述】:

我正在编写一个 Python 脚本,该脚本有时需要用户输入输入。我在 macOS Sierra 上使用 bash。

为了接收输入,我写了以下内容:

import readline  # gnureadline 6.3.8

START = '\033[91m\033[1m'
END = '\033[0m'

response = raw_input(START + 'Enter text: ' + END)

我使用START 和END 中的ANSI 转义序列来直观地区分脚本的提示和用户的文本输入。

不幸的是,一旦我开始输入文本,程序就会忘记用户输入文本的实际开始位置。下面的第一克拉是 CTRLA 现在映射到的位置,第二克拉是 CTRLE 带我的位置。箭头键同样认为用户输入的开始和结束是偏移的,如图所示。

Enter text: hello my name is             
                         ^               ^  

我尝试了一些方法来调试它。

  1. 我尝试在提示符和文本条目之间添加一个换行符,但这只会使偏移变差。

  2. 如果我只使用箭头键,而不使用 CTRLA、CTRLE,选项箭头导航字符串,这按预期工作。也就是说,考虑到用户输入的字符串的长度和复杂性,仅使用箭头键在字符串中移动会让用户感到痛苦。

  3. 最重要的是,如果我根本不使用START 和END,这将非常有效。也就是说,脚本的可用性下降了——很难从该脚本完整版中的所有其他文本中找出提示。

我有什么技巧可以使用 ANSI 转义序列来格式化提示,而不会破坏用户使用 CTRLA, CTRLE 和选项箭头?谢谢!

【问题讨论】:

  • 如果你先print(START + 'Enter text: ' + END, end='') 然后response = raw_input() 呢?我没有在口译员附近尝试这个,只是一个想法。
  • Readline 是否支持带有 \[ 和 \] 的非打印序列的 Bash $PS1 样式标记?顺便说一句,更喜欢使用 tput 作为便携式终端代码 - 并非每个终端都是 VT220!
  • @ndmeiri end='' 语法对我不起作用(Python 2.7.15),但是将提示符和 raw_input 分成两个单独的调用似乎可以解决问题(尽管它引入了一个越线)。谢谢!
  • @TAH 太好了。我将扩展并添加它作为答案
  • \[ 和 \] 是特定于提示的,但它们代表 Readline 本身通常使用的 \001 和 \002 (IIRC)。

标签: python bash ansi-escape


【解决方案1】:

Readline 期望 \001 和 \002 作为不可见字符周围的标记:

import readline  # gnureadline 6.3.8

START = '\001\033[91m\033[1m\002'
END = '\001\033[0m\002'

response = raw_input(START + 'Enter text: ' + END)

使用以\001 为前缀并以\002 为后缀的ANSI 转义序列,GNU readline 将知道在确定提示字符串的长度时应排除这些字符。

【讨论】:

    【解决方案2】:

    分别打印提示和要求输入到两个命令中。

    Python 3.x

    print(START + 'Enter text: ' + END, end='')
    response = input()
    

    Python 2.x

    import sys
    
    # Use sys.stdout.write to avoid printing a trailing newline.
    sys.stdout.write(START + 'Enter text: ' + END)
    response = raw_input()
    

    【讨论】:

    • 感谢您添加有关避免尾随换行符的内容!
    【解决方案3】:

    在我的情况下,接受的答案没有解决。

    我开始了

    START = '\x1b[7m\x1b[37m' # white on black
    END = '\x1b[0m'  # reset
    response = input(START + 'QUERY ' + END)
    

    同样的结果

    QUERY hello my name is hello my name is
                  ^                                ^
                  hello my name is hello my name is
    

    使用上面的解决方案,

    print(START + 'QUERY ' + END, end='')
    response = input()
    

    导致它考虑从开头开始的行

    QUERY hello my name is hello my name is
    ^                                ^
    hello my name is hello my name is
    

    可能是因为 input("") 的长度为 0 个字符。

    知道这些控制字符被计为偏移量,我们可以使用它们再次创建偏移量。

    我的文字 QUERY 有 6 个字符长,所以我可以使用

    print(START + 'QUERY ' + END, end='')
    response = input('\033[D\033[C')
    

    因为Cursor Forward, Cursor Back '\033', '[', 'D', '\033', '[', 'C' 正在欺骗 readline 偏移 6 个字符。

    QUERY hello my name is hello my name is
    \[D\[C^                                ^
          hello my name is hello my name is
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-14
      • 1970-01-01
      • 2011-06-18
      • 1970-01-01
      • 2011-09-27
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      相关资源
      最近更新 更多