简体   繁体   English

使用Python的彩色终端文本效果

[英]colour terminal text effects with Python

I'm trying to implement colour cycling on my text in Python, ie i want it to cycle through the colour of every character typed (amongst other effects) My progress so far has been hacked together from an ansi colour recipe improvement suggestions welcomed. 我正在尝试在Python中的文本上实现颜色循环,即我希望它可以循环显示键入的每个字符的颜色(以及其他效果)。到目前为止,我的进步已经受到了ansi颜色配方改进建议的欢迎。

I was also vaguely aware of, but never used: termcolor , colorama , curses 我也隐约意识到,但从未使用过: termcolorcoloramacurses

during the hack i managed to make the attributes not work (ie reverse blink etc) and its not perfect probably mainly because I dont understand these lines properly: 在hack期间,我设法使属性不起作用(例如,反向闪烁等)并且其不完美,可能主要是因为我不正确地理解这些行:

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

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

if anyone can clarify that a bit, I would appreciate it. 如果有人可以澄清一下,我将不胜感激。 this runs and does something, but its not quite there. 它可以运行并执行某些操作,但是还不完全正确。 I changed the code so instead of having to separate colour commands from your string you can include them. 我更改了代码,因此不必将颜色命令与字符串分开,可以包含它们。

 #!/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

should also mention that i have absolutely no idea what this line does :) - well i see that it puts colours into a dictionary object, but how it does it is confusing. 还应该提到,我绝对不知道这行的作用:)-好吧,我看到它将颜色放入字典对象中,但是它的作用却令人困惑。 not used to this python syntax yet. 还不习惯这种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()))

This is a rather convoluted code - but, sticking to you r question, about the lines: 这是一个令人费解的代码-但是,对于您来说,关于行的问题是:

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

This expression appends to the list named cmd the interpolation of the string contained in the variable format with the result of the expression (colours[tmpword]+fgoffset)) - which concatenates the code in the color table (colours) named by tmpword with fgoffset . 此表达式将变量format包含的字符串的内插值与表达式结果(colours[tmpword]+fgoffset))附加到名为cmd的列表中-该表达式将(colours[tmpword]+fgoffset))命名的颜色表(颜色)中的tmpwordfgoffset

The format string contains '1;%dm' which means it expects an integer number, whcih will replace the "%d" inside it. format字符串包含'1;%dm' ,这意味着它需要一个整数,它将替换其中的“%d”。 (Python's % string substitution inherits from C's printf formatting) . (Python的%字符串替换继承自C的printf格式)。 You "colours" color table ont he other hand is built in a convoluted way I'd recomend in no code, setting directly the entry in "globals" for it - but let's assume it does have the correct numeric value for each color entry. 您可以用另一种方式为颜色表“上色”,我不推荐使用任何代码,直接在“ globals”中设置该项-但让我们假设每个颜色项都有正确的数值。 In that case, adding it to fgoffset will generate color codes out of range (IRCC, above 15) for some color codes and offsets. 在这种情况下,将其添加到fgoffset将为某些颜色代码和偏移生成超出范围的颜色代码(IRCC,大于15)。

Now the second line in which you are in doubt: 现在您不确定的第二行:

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

This if is just Python's ternary operator - equivalent to the C'ish expr?:val1: val2 if这仅仅是Python的三元运算符-相当于C'ish expr?:val1: val2

It is equivalent to: 它等效于:

if tmpword in attrs: c = format % attrs[tmpword] else: c = format % None 如果attrs中的tmpword:c =格式%attrs [tmpword]否则:c =格式%无

Note that it has less precedence than the % operator. 请注意,它的优先级低于%运算符。 Maybe you would prefer: 也许您更喜欢:

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

instead 代替

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM