【问题标题】:colour terminal text effects with Python使用 Python 的颜色终端文本效果
【发布时间】:2011-11-29 12:36:11
【问题描述】:

我正在尝试在 Python 中对我的文本实现颜色循环,即我希望它在输入的每个字符的颜色之间循环(以及其他效果)我到目前为止的进展已经从 ansi colour recipe 改进建议中得到了破解欢迎。

我也隐约知道,但从未使用过:termcolorcoloramacurses

在 hack 期间,我设法使属性不起作用(即反向闪烁等)并且它并不完美可能主要是因为我不正确理解这些行:

cmd.append(format % (colours[tmpword]+fgoffset))

c=format % attrs[tmpword] if tmpword in attrs else None

如果有人能澄清一下,我将不胜感激。这运行并做了一些事情,但它并不完全存在。我更改了代码,因此不必将颜色命令与您的字符串分开,您可以包含它们。

 #!/usr/bin/env python

'''
        "arg" is a string or None
        if "arg" is None : the terminal is reset to his default values.
        if "arg" is a string it must contain "sep" separated values.
        if args are found in globals "attrs" or "colors", or start with "@" \
    they are interpreted as ANSI commands else they are output as text.
        @* commands:

            @x;y : go to xy
            @    : go to 1;1
            @@   : clear screen and go to 1;1
        @[colour] : set foreground colour
        ^[colour] : set background colour

        examples:
    echo('@red')                  : set red as the foreground color
    echo('@red ^blue')             : red on blue
    echo('@red @blink')            : blinking red
    echo()                       : restore terminal default values
    echo('@reverse')              : swap default colors
    echo('^cyan @blue reverse')    : blue on cyan <=> echo('blue cyan)
    echo('@red @reverse')          : a way to set up the background only
    echo('@red @reverse @blink')    : you can specify any combinaison of \
            attributes in any order with or without colors
    echo('@blink Python')         : output a blinking 'Python'
    echo('@@ hello')             : clear the screen and print 'hello' at 1;1

colours:
{'blue': 4, 'grey': 0, 'yellow': 3, 'green': 2, 'cyan': 6, 'magenta': 5, 'white': 7, 'red': 1}



    '''

'''
    Set ANSI Terminal Color and Attributes.
'''
from sys import stdout
import random
import sys
import time

esc = '%s['%chr(27)
reset = '%s0m'%esc
format = '1;%dm'
fgoffset, bgoffset = 30, 40
for k, v in dict(
    attrs = 'none bold faint italic underline blink fast reverse concealed',
    colours = 'grey red green yellow blue magenta cyan white'
).items(): globals()[k]=dict((s,i) for i,s in enumerate(v.split()))
bpoints = ( " [*] ", " [!] ", )

def echo(arg=None, sep=' ', end='\n', rndcase=True, txtspeed=0.03, bnum=0):

    cmd, txt = [reset], []
    if arg:
            if bnum != 0:
                    sys.stdout.write(bpoints[bnum-1])

        # split the line up into 'sep' seperated values - arglist
            arglist=arg.split(sep)

        # cycle through arglist - word seperated list 
            for word in arglist:

                if word.startswith('@'):
            ### First check for a colour command next if deals with position ###
                # go through each fg and bg colour  
                tmpword = word[1:]
                    if tmpword in colours:
                        cmd.append(format % (colours[tmpword]+fgoffset))
                    c=format % attrs[tmpword] if tmpword in attrs else None
                    if c and c not in cmd:
                                cmd.append(c)
                    stdout.write(esc.join(cmd))
                    continue
                # positioning (starts with @)
                word=word[1:]
                if word=='@':
                    cmd.append('2J')
                    cmd.append('H')
                    stdout.write(esc.join(cmd))
                    continue
                else:
                    cmd.append('%sH'%word)
                    stdout.write(esc.join(cmd))
                    continue

                if word.startswith('^'):
            ### First check for a colour command next if deals with position ###
                # go through each fg and bg colour  
                tmpword = word[1:]
                    if tmpword in colours:
                        cmd.append(format % (colours[tmpword]+bgoffset))
                    c=format % attrs[tmpword] if tmpword in attrs else None
                    if c and c not in cmd:
                                cmd.append(c)
                    stdout.write(esc.join(cmd))
                    continue                    
            else:
                for x in word:  
                    if rndcase:
                        # thankyou mark!
                        if random.randint(0,1):
                                x = x.upper()
                        else:
                            x = x.lower()
                    stdout.write(x)
                    stdout.flush()
                    time.sleep(txtspeed)
                stdout.write(' ')
                time.sleep(txtspeed)
    if txt and end: txt[-1]+=end
    stdout.write(esc.join(cmd)+sep.join(txt))

if __name__ == '__main__':

    echo('@@') # clear screen
    #echo('@reverse') # attrs are ahem not working
    print 'default colors at 1;1 on a cleared screen'
    echo('@red hello this is red')
    echo('@blue this is blue @red i can ^blue change @yellow blah @cyan the colours in ^default the text string')
    print
    echo()
    echo('default')
    echo('@cyan ^blue cyan blue')
    print
    echo()
    echo('@cyan this text has a bullet point',bnum=1)
    print
    echo('@yellow this yellow text has another bullet point',bnum=2)
    print
    echo('@blue this blue text has a bullet point and no random case',bnum=1,rndcase=False)
    print
    echo('@red this red text has no bullet point, no random case and no typing effect',txtspeed=0,bnum=0,rndcase=False)
#   echo('@blue ^cyan blue cyan')
    #echo('@red @reverse red reverse')
#    echo('yellow red yellow on red 1')
#    echo('yellow,red,yellow on red 2', sep=',')
#    print 'yellow on red 3'

#        for bg in colours:
#                echo(bg.title().center(8), sep='.', end='')
#                for fg in colours:
#                        att=[fg, bg]
#                        if fg==bg: att.append('blink')
#                        att.append(fg.center(8))
#                        echo(','.join(att), sep=',', end='')

    #for att in attrs:
    #   echo('%s,%s' % (att, att.title().center(10)), sep=',', end='')
    #   print

    from time import sleep, strftime, gmtime
    colist='@grey @blue @cyan @white @cyan @blue'.split()
    while True:
        try:
            for c in colist:
                sleep(.1)
                echo('%s @28;33 hit ctrl-c to quit' % c,txtspeed=0)
                echo('%s @29;33 hit ctrl-c to quit' % c,rndcase=False,txtspeed=0)
            #echo('@yellow @6;66 %s' % strftime('%H:%M:%S', gmtime()))
        except KeyboardInterrupt:
            break
        except:
            raise
    echo('@10;1')
    print

还应该提到我完全不知道这条线做了什么:) - 我看到它将颜色放入字典对象,但它是如何工作的却令人困惑。还不习惯这种 python 语法。

for k, v in dict(
    attrs = 'none bold faint italic underline blink fast reverse concealed',
    colours = 'grey red green yellow blue magenta cyan white'
).items(): globals()[k]=dict((s,i) for i,s in enumerate(v.split()))

【问题讨论】:

  • 要在 Python 字符串中插入特殊字符,您可以使用 "\xHH" 转义,其中 HH 是字符代码的十六进制。因此,不需要esc = '%s['%chr(27) - 只需esc = '\x1b' 就可以了
  • 啊,好吧,我改变一下,谢谢。我认为这是一个全面的 txt 效果类型模块,也许我应该在课堂上重新考虑它,而不是我知道如何上课,但我想不通:)

标签: python colors


【解决方案1】:

这是一个相当复杂的代码 - 但是,坚持你的问题,关于以下几行:

cmd.append(format % (colours[tmpword]+fgoffset))

此表达式将包含在变量 format 中的字符串与表达式 (colours[tmpword]+fgoffset)) 的结果附加到名为 cmd 的列表中,该表达式将@987654325 命名的颜色表(颜色)中的代码连接起来@ 和fgoffset

format 字符串包含'1;%dm',这意味着它需要一个整数,它将替换其中的“%d”。 (Python 的 % 字符串替换继承自 C 的 printf 格式)。另一方面,您的“颜色”颜色表是以一种复杂的方式构建的,我不建议使用任何代码,直接为它设置“全局”中的条目 - 但我们假设它确实具有每个颜色条目的正确数值。在这种情况下,将其添加到fgoffset 会为某些颜色代码和偏移生成超出范围(IRCC,15 以上)的颜色代码。

现在是您有疑问的第二行:

c=format % attrs[tmpword] if tmpword in attrs else None

if 只是 Python 的三元运算符 - 相当于 C'ish expr?:val1: val2

相当于:

如果 attrs 中有 tmpword: c = 格式 % attrs[tmpword] 别的: c = 格式 % 无

请注意,它的优先级低于% 运算符。 也许你更喜欢:

c= (format % attrs[tmpword]) if tmpword in attrs else ''

改为

【讨论】:

  • 嘿!多谢!这对我来说真的很清楚。是的,它有点工作,但它是一个丑陋的黑客,我试图做得更好。我应该提到我是一个完全的初学者,我试图理解所有这些东西。我不明白您对以错综复杂的方式构建的颜色表是什么意思?非常感谢任何改进。哦,我在颜色表中打印了一个打印出来的数字,它在 cmets 中,只是为了检查数字是否正常。它似乎工作。
  • 至于“复杂的方式”——在 Python 中,我们非常重视可读性,作为其中的一部分,修改由“globals()”返回的字典应该只在极端情况下进行——所以,简化代码开头的一个示例是将for k, v in dict( ... enumerate(v.split())) 行替换为以下两行:attrs = dict ((name, val) for val, name in enumerate('none bold faint italic underline blink fast reverse concealed' .split()))colours = dict((name, val) for val, name in enumerate('grey red green yellow blue magenta cyan white' .split()))
  • 好吧,我把它放进去,现在正试图把它转换成一个类。再次感谢老兄。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-19
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2023-01-14
相关资源
最近更新 更多