Python:字典值中的八进制转义字符\033在打印语句中被翻译为UTF-8字符

11
我一直在尝试在终端和Python 2.7.3中使用彩色输出。 ANSI颜色代码总是在终端中完美呈现,只有一个小问题,我还不能确定它的确切位置,只能将其归结为这个特定字典定义。
以下是导致困惑的原因:
color = {
    'white':    "\033[1,37m",
    'yellow':   "\033[1,33m",
    'green':    "\033[1,32m",
    'blue':     "\033[1,34m",
    'cyan':     "\033[1,36m",
    'red':      "\033[1,31m",
    'magenta':  "\033[1,35m",
    'black':    "\033[1,30m",
    'darkwhite':  "\033[0,37m",
    'darkyellow': "\033[0,33m",
    'darkgreen':  "\033[0,32m",
    'darkblue':   "\033[0,34m",
    'darkcyan':   "\033[0,36m",
    'darkred':    "\033[0,31m",
    'darkmagenta':"\033[0,35m",
    'darkblack':  "\033[0,30m",
    'off':        "\033[0,0m"
}

yellow = "\033[1;33m"
off = "\033[0;0m"

print color['yellow'] + "string to render" + color['off']     # fails to render properly
print "%(yellow)sstring to render%(off)s" % color             # ditto
print "%sstring to render%s" % (color['yellow'], color['off'])# ditto

print yellow + "string to render" + off                       # as intended

pp = pprint.PrettyPrinter(indent=6)
pp.pprint(color)
输出结果如下:
{ 'black': '\x1b[1,30m',
  'blue': '\x1b[1,34m',
  'cyan': '\x1b[1,36m',
  'darkblack': '\x1b[0,30m',
  'darkblue': '\x1b[0,34m',
  'darkcyan': '\x1b[0,36m',
  'darkgreen': '\x1b[0,32m',
  'darkmagenta': '\x1b[0,35m',
  'darkred': '\x1b[0,31m',
  'darkwhite': '\x1b[0,37m',
  'darkyellow': '\x1b[0,33m',
  'green': '\x1b[1,32m',
  'magenta': '\x1b[1,35m',
  'off': '\x1b[0,0m',
  'red': '\x1b[1,31m',
  'white': '\x1b[1,37m',
  'yellow': '\x1b[1,33m'}

这似乎是将内容正确转换为十六进制格式的适当翻译。尽管如此,字典值无法正确传递给打印语句。无论使用原始字符串还是Unicode字符串文字修饰符都不能改变任何东西。我肯定漏掉了一些非常明显的东西。在不支持UTF-8的终端上,Unicode字符被省略。

我已经看到了关于termcolor的实现:

if os.getenv('ANSI_COLORS_DISABLED') is None:
    fmt_str = '\033[%dm%s'
    if color is not None:
        text = fmt_str % (COLORS[color], text)

    if on_color is not None:
        text = fmt_str % (HIGHLIGHTS[on_color], text)

    if attrs is not None:
        for attr in attrs:
            text = fmt_str % (ATTRIBUTES[attr], text)

    text += RESET
return text

colorama:

CSI = '\033['
def code_to_chars(code):
    return CSI + str(code) + 'm'
class AnsiCodes(object):
    def __init__(self, codes):
        for name in dir(codes):
            if not name.startswith('_'):
                value = getattr(codes, name)
                setattr(self, name, code_to_chars(value))

还有其他几个。从分析的角度来看,它们都避免在字典中定义整个序列。我确实同意这种方法在词汇上是合理的。然而,事实仍然存在,即除了Perl哈希、C++的vectormap <string,string>或类似于映射的C的structchar *string之外,不能正确解释字典值中的转义字符。

这就引出了一个问题:是否有特定的原因,根据标准(如果可能的话),使字典(我们称之为:)插值与普通字符串不同?


这是已经修复的颜色代码字典(如果编辑,则使用制表符缩进,SO似乎会剥离制表符以进行阅读):

color = {
    'white':    "\033[1;37m",
    'yellow':   "\033[1;33m",
    'green':    "\033[1;32m",
    'blue':     "\033[1;34m",
    'cyan':     "\033[1;36m",
    'red':      "\033[1;31m",
    'magenta':  "\033[1;35m",
    'black':      "\033[1;30m",
    'darkwhite':  "\033[0;37m",
    'darkyellow': "\033[0;33m",
    'darkgreen':  "\033[0;32m",
    'darkblue':   "\033[0;34m",
    'darkcyan':   "\033[0;36m",
    'darkred':    "\033[0;31m",
    'darkmagenta':"\033[0;35m",
    'darkblack':  "\033[0;30m",
    'off':        "\033[0;0m"
}

你用的是什么操作系统/终端呢? - Paulo Bu
Linux,问题现已解决,无论如何还是谢谢! - Nicholas
这是截至2021年5月的colorama实现的更新链接:https://github.com/tartley/colorama/blob/master/colorama/ansi.py - Kapocsi
1个回答

9
我查看了你的源代码,我认为问题出在字典中颜色定义上。
如果你仔细观察,你的颜色字典值类似于白色的\033[1,30m。然而,它应该是\033[1;30m。请注意,你使用了逗号,(comma)字符而不是分号;(semicolon)字符。作为测试,我创建了一个颜色字典子集,并运行了这些测试。
>>> color = {'white' :'\033[1;37m', 'yellow':'\033[1;33m', 'off' : '\033[0;0m'}
>>> print color['white'] + 'string' + color['off']
string   #this string is white in color
>>> print color['yellow'] + 'string' + color['off']
string #this string is yellow in color
>>> color['yellow'] = '\033[1,33m' #incorrect color code - using a , character instead of ;
>>> print color['yellow'] + 'string' + color['off']
string   #prints the string in console default color i.e. not in yellow color
>>> 

希望这能有所帮助。

这可能是问题所在,ANSI转义码颜色使用分号作为分隔符。 - martineau
哦,太感谢你有耐心并且仔细地查看我的代码。我从另一个Perl脚本中复制了这部分,并在vim中进行了错误的正则表达式替换。再次感谢您的关注! - Nicholas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接