python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色) 
前言 
在 python 开发中,有时候想通过cmd窗口来和用户交互,比如显示信息之类的,会比自己创建 GUI 来的方便,但是随之而来的就是编码乱码问题  
下面例子在 python2 和 python3 中都可以运行,也可以在其它 .py 中通过 import os;os.startfile(ur"xxx.bat") 来运行  
之前一直遇到一个问题,通过双击 bat 文件来运行,可以不用转码,只要 cmd 窗口的活动页编码是 936 就可以了,但是在其它 py 文件中运行那个 bat,就会出现乱码,所以转码后可以一保正常  
双击 .bat 来运行 py 
 
 @echo off chcp 936>nul python d:\test.py
exit  
  
 
 # -*- coding: utf-8-*-
import sys
import os
input_ = input
zh_coding = 'cp936'
utf_8 = 'utf-8'
# before other codes
if sys.version_info.major < 3:
    reload(sys)
    sys.setdefaultencoding(utf_8)
    
    input_ = raw_input
# begin your code
def to936(utf8):
    if sys.version_info.major < 3:
        utf8 = utf8.decode().encode(zh_coding)
    return utf8
def toUtf8(zh936):
    if sys.version_info.major < 3:
        zh936 = zh936.decode(zh_coding).encode(utf_8)
    return zh936
os.system('@echo off')
# 转换cmd窗口的编码集,不管cmd窗口的默认值是什么都显示正确
os.system('chcp 936 >nul')
print(to936(u'中文简体(encoding)'))
print(to936(u'中文繁體(encoding)'))
# 在 cmd 窗口 的默认值的默认代码页不是 936 的情况下会报错。
# 如果是 936,通过双击 .bat 运行是正常的,
# 如果在其它 py 中通过 os.startfile(), subprocess, os.system()
# 等模块来运行那个bat,会显示乱码
try:
    print(u'中文简体(not encoding)')
    print(u'中文繁體(not encoding)')
except Exception as e:
    os.system(to936(u'echo 解码错误'))
    print(e)
i = input_(to936(u'输入你的中文名字:'))
i = toUtf8(i)
msg = to936(u'你的中文名字是:%s' % i)
print(msg)
os.system('pause && exit') 
  
 打印不同颜色 
win 的 cmd 终端也可以像linux的终端一样,打印不同行颜色,同一行不同颜色  
这里有个个方法:https://www.cnblogs.com/linyfeng/p/8286506.html#4304331  
不过,在我使用 waf 的过程中,发现 waf 在win cmd 窗口打印颜色更全面更通用的模块,使用方法和linux的一致  
waf 是开源的,我从里面提取了相关的模块,可以集成到自己 lib 中,waf 教程和下载:https://waf.io/book/  
而且,使用 waf 的模块,在 python 2 中只是print 的时候,不用转码,但是input的时候还是要转回utf-8  
waf 从 git 上下载的 waflib 兼容 python 2 和 3  
waflib模块中提取的文件(注意,这些文件的编写,语法缩进是 tab,而不是四个空格,所以最好自己把 tab 替换成四个空格,不然通过编译出来的 pyc 可能不能用):  
__init__.py  
ansiterm.py  
Errors.py  
Utils.py  
 
 # -*- coding: utf-8-*-
import sys
import os
input_ = input
zh_coding = 'cp936'
utf_8 = 'utf-8'
# before other codes
if sys.version_info.major < 3:
    reload(sys)
    sys.setdefaultencoding(utf_8)
# begin your code ###################################################
from waflib import ansiterm
if not os.environ.get('NOSYNC',False):
    if sys.stdout.isatty()and id(sys.stdout)==id(sys.__stdout__):
        sys.stdout=ansiterm.AnsiTerm(sys.stdout)
    if sys.stderr.isatty()and id(sys.stderr)==id(sys.__stderr__):
        sys.stderr=ansiterm.AnsiTerm(sys.stderr)
os.system('@echo off')
# 转换cmd窗口的编码集,不管cmd窗口的默认值是什么都显示正确
os.system('chcp 936 >nul')
# 颜色
print(u'\033[32m绿色\033[31m红色\033[0m')
print(u'中文简体(not encoding)')
print(u'中文繁體(not encoding)')
os.system('pause && exit') 
  
上面没有 input 例子,如果要用,参考上上个例子  
主要添加了以下代码,之后 print 就像通用的一样使用就可以了  
 
 from waflib import ansiterm
if not os.environ.get('NOSYNC',False):
    if sys.stdout.isatty()and id(sys.stdout)==id(sys.__stdout__):
        sys.stdout=ansiterm.AnsiTerm(sys.stdout)
    if sys.stderr.isatty()and id(sys.stderr)==id(sys.__stderr__):
        sys.stderr=ansiterm.AnsiTerm(sys.stderr) 
  
 print 颜色 格式参考:https://www.cnblogs.com/pupilheart/p/9704943.html  
   
   |