在输出到STDOUT和日志文件时去除ANSI颜色编码

11 投票
3 回答
6692 浏览
提问于 2025-04-15 23:03

我有一些函数可以给我的屏幕消息加颜色:

def error(string):
    return '\033[31;1m' + string + '\033[0m'

def standout(string):
    return '\033[34;1m' + string + '\033[0m'

我这样使用它们:

print error('There was a problem with the program')
print "This is normal " + standout("and this stands out")

我想把输出记录到一个文件里(除了在屏幕上显示),但是不想在每个print语句里再加一行“记录”的代码,而且希望输出的内容里没有ANSI颜色代码。

原因是,如果你直接用python program.py > out,那么文件out里会包含ANSI颜色代码,这在普通文本编辑器里打开时看起来非常糟糕。

有没有什么建议?

3 个回答

2

下面unubtu的回答很好,但我觉得MyFormatter需要稍微修改一下,以确保在format()方法中能正确格式化。

class MyFormatter(logging.Formatter):
        def format(self,record):
            msg = super(MyFormatter, self).format(record)
            return plain(msg)
7

如果你想同时在终端和日志文件中打印信息,我建议你使用日志模块。你甚至可以定义一个自定义的格式,这样记录到文件时就不会有终端的颜色代码了:

import optparse
import logging

def error(string):
    return '\033[31;1m' + string + '\033[0m'

def standout(string):
    return '\033[34;1m' + string + '\033[0m'

def plain(string):
    return string.replace('\033[34;1m','').replace('\033[31;1m','').replace('\033[0m','')

if __name__=='__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='%(message)s',
                        filemode='w')
    logger=logging.getLogger(__name__)    
    def parse_options():    
        usage = 'usage: %prog [Options]'
        parser = optparse.OptionParser()
        parser.add_option('-l', '--logfile', dest='logfile', 
                          help='use log file')
        opt,args = parser.parse_args()
        return opt,args
    opt,args=parse_options()
    if opt.logfile:
        class MyFormatter(logging.Formatter):
            def format(self,record):
                return plain(record.msg)
        fh = logging.FileHandler(opt.logfile)
        fh.setLevel(logging.INFO)
        formatter = MyFormatter('%(message)s')
        fh.setFormatter(formatter)
        logging.getLogger('').addHandler(fh)

    logger.info(error('There was a problem with the program'))
    logger.info("This is normal " + standout("and this stands out"))

test.py 只会在终端打印信息。

test.py -l test.out 会同时在终端和文件 test.out 中打印信息。

无论哪种情况,终端显示的文本都有颜色代码,而日志记录的文本则没有。

11

sys.stdout.isatty这个函数可能会对你有帮助:

from sys import stdout

def error(string, is_tty=stdout.isatty()):
    return ('\033[31;1m' + string + '\033[0m') if is_tty else string

def standout(string, is_tty=stdout.isatty()):
    return ('\033[34;1m' + string + '\033[0m') if is_tty else string

其实这是我能想到的为数不多的可以使用默认参数而不是设置为None的情况,因为在Python中,默认参数是在编译时就确定的,而不是像C++那样在运行时才确定……

另外,如果你真的需要的话,可以明确地覆盖这个行为,不过这并不能让你在重定向时操作stdout本身。你有没有考虑过使用logging模块呢?(也许你之前不知道这个模块?)

撰写回答