解决Python3中的中文字符编码的问题-亲测有效
解决Python3中的中文字符编码的问题
一、原理篇:
Unicode是一32位编码格式,不适合用来传输和存储,所以必须转换成utf-8,gbk等等。这篇文章主要介绍了Python3中的解决中文字符编码的问题,需要的朋友可以参考下
python3中str默认为Unicode的编码格式
Unicode是一32位编码格式,不适合用来传输和存储,所以必须转换成utf-8,gbk等等
所以在Python3中必须将str类型转换成bytes类型的
在Python中使用encode的方式可以进行字符的编码
实际用法:
1 2 3 4 5 |
|
总结:
- Python中str类型转bytes类型,相当与Unicode转gbk,utf-8。。。类型
- b'代表字符编码格式为bytes,
- utf-8默认24位占3个8位16进制数
- gbk中国编码默认占16位2个8位16进制数字
二、实战篇:
对于在Python代码中直接操作中文汉字的情况,可以考虑在代码文件头部加入万能注释,例如:
#coding = <gbk>
来个小小的例子,在vscode或者其他Python开发工具中(系统自带终端亦同,须正确安装Python开发调试环境,不会的请自行搜索或查看本博主其他文章),我们创建一个名字为“each.py”使用each遍历数组中的成员,目的是把中国古代王朝顺序和主要皇帝姓氏捋一捋,就可以在文件头加入上述的万能注释,以保无虞。示例代码如下:
#coding = <gbk>
member = ['夏','商','西周','东周','秦','西楚','西汉','西汉','东汉','三国(曹魏、蜀汉、东吴)','西晋','东晋','五胡十六国','南朝(宋、齐、梁、陈)','北朝(北魏、东魏、北齐、西魏、北周)','隋朝','唐朝','五代十国','宋(北宋、南宋)','辽','西夏','金','元','明','清','中华民国','中华人民共和国']
for each in member:
print(each,len(member))
print('\n''\n')
emperor = ['刘(汉、蜀汉、前赵、南朝宋、南汉、北汉)52位','刘氏建立的正统政权为9个','李(成汉、唐、西凉、后唐、南唐、西夏)50位','李氏建立的正统政权为6个','朱(后梁、明)26位','赵(宋)18位','萧(梁、西梁)17位','司马(晋)16位','高(北燕、北齐、南平)12位','王(新、前蜀、闽)10位','石(后赵、后晋)9位','陈(陈)8位','杨(隋、五代十国·吴)7位','张(前凉)7位','马(五代楚)6位','曹(三国魏)5位','钱(吴越)5位','孙(三国吴)4位','冯(北燕)2位','孟(后蜀)2位','段(西燕、北凉)2位','赢(秦)2位','柴(后周)2位','孛儿只斤氏(元、北元)19位','慕容氏(前燕、后燕、西燕)16位','耶律氏(辽)15位','爱新觉罗氏(清)12位','元(北魏、东魏、西魏)11位','完颜氏(金)10位','元氏之前身拓跋氏(北魏)8位','苻(前秦)7位','宇文氏(北周)5位','乞伏氏(西秦)4位','沮渠氏(北凉)4位','秃发氏(南凉)3位','赫连氏(大夏)3位','姚(后秦)3位','吕(后凉)3位等']
for each in emperor:
print(each,len(emperor))
在命令模式下进入到 each.py文件所在目录(linux 和MacOS下都使用cd命令,我的存在用户目录“ ~/pythonlab/”下,即可用 “cd ~/pythonlab/”即可进入,ls命令看到each.py后,即可执行运行命令,不会的自行搜索,不再赘述)
执行Python运行命令运行each.py:
(本人安装的是Python3.9的版本,故用的是python3命令启动运行)
python3 each.py
即可看到如下输出结果:
MacBook-Pro:pythonlab tony$ python3 each.py
夏 27
商 27
西周 27
东周 27
秦 27
西楚 27
西汉 27
西汉 27
东汉 27
三国(曹魏、蜀汉、东吴) 27
西晋 27
东晋 27
五胡十六国 27
南朝(宋、齐、梁、陈) 27
北朝(北魏、东魏、北齐、西魏、北周) 27
隋朝 27
唐朝 27
五代十国 27
宋(北宋、南宋) 27
辽 27
西夏 27
金 27
元 27
明 27
清 27
中华民国 27
中华人民共和国 27
刘(汉、蜀汉、前赵、南朝宋、南汉、北汉)52位 38
刘氏建立的正统政权为9个 38
李(成汉、唐、西凉、后唐、南唐、西夏)50位 38
李氏建立的正统政权为6个 38
朱(后梁、明)26位 38
赵(宋)18位 38
萧(梁、西梁)17位 38
司马(晋)16位 38
高(北燕、北齐、南平)12位 38
王(新、前蜀、闽)10位 38
石(后赵、后晋)9位 38
陈(陈)8位 38
杨(隋、五代十国·吴)7位 38
张(前凉)7位 38
马(五代楚)6位 38
曹(三国魏)5位 38
钱(吴越)5位 38
孙(三国吴)4位 38
冯(北燕)2位 38
孟(后蜀)2位 38
段(西燕、北凉)2位 38
赢(秦)2位 38
柴(后周)2位 38
孛儿只斤氏(元、北元)19位 38
慕容氏(前燕、后燕、西燕)16位 38
耶律氏(辽)15位 38
爱新觉罗氏(清)12位 38
元(北魏、东魏、西魏)11位 38
完颜氏(金)10位 38
元氏之前身拓跋氏(北魏)8位 38
苻(前秦)7位 38
宇文氏(北周)5位 38
乞伏氏(西秦)4位 38
沮渠氏(北凉)4位 38
秃发氏(南凉)3位 38
赫连氏(大夏)3位 38
姚(后秦)3位 38
吕(后凉)3位等 38
说明一下:关于代码中的朝代和皇帝姓氏等数据来源于网络,不确保正确与否,历史学家和较真的朋友请自动飘过,本小白是历史盲,不喜勿喷,我们的目的是演示Python开发中的编程思维和解决技术问题的纯技术思路,熟知历史和探讨历史的求饶放过。
关于“如何解决Python3中的中文字符编码的问题”,应该还有其他的方法,有好的思路和经验的朋友们欢迎评论贡献,互相学习,感激不尽^_^
扩展阅读:
附上:Python官方关于此问题解决方案
PEP 263-定义Python源代码编码
PEP: | 263 |
---|---|
标题: | 定义Python源代码编码 |
作者: | 马尔在lemburg.com(马克·安德烈·伦伯格),马丁在v.loewis.de(马丁·冯·洛维斯) |
状态: | 最后 |
类型: | 标准跟踪 |
创建时间: | 2001年6月6日 |
Python版本: | 2.3 |
历史后: |
抽象
该PEP建议引入一种语法,以声明Python源文件的编码。然后,Python解析器将使用编码信息使用给定的编码来解释文件。最值得注意的是,这增强了源代码中Unicode文字的解释,并使得可以在例如Unicode的编辑器中直接使用UTF-8编写Unicode文字。
问题
在Python 2.1中,只能使用基于Latin-1的编码“ unicode-escape”编写Unicode文字。这使得编程环境对在许多亚洲国家/地区以外的非Latin-1语言环境中生活和工作的Python用户而言相当不利。程序员可以使用最喜欢的编码来编写其8位字符串,但是绑定到Unicode文字的“ unicode-escape”编码。
拟议的解决方案
我建议通过在文件顶部使用特殊注释来声明该编码,从而使每个源文件都可以看到和更改Python源代码编码。
为了使Python知道此编码声明,在处理Python源代码数据方面需要进行一些概念上的更改。
定义编码
如果没有其他编码提示,Python将默认使用ASCII作为标准编码。
要定义源代码编码,必须将魔术注释作为源文件的第一行或第二行放置在源文件中,例如:
<span style="color:#444444">#coding = <编码名称>
</span>
或(使用流行的编辑器认可的格式):
<span style="color:#444444">#!/ usr / bin / python
#-*-编码:<编码名称>-*-
</span>
要么:
<span style="color:#444444">#!/ usr / bin / python
#vim:设置fileencoding = <编码名称>:
</span>
更准确地说,第一行或第二行必须匹配以下正则表达式:
<span style="color:#444444">^ [\ t \ f] *#。*?编码[:=] [\ t] *([-_。a-zA-Z0-9] +)
</span>
然后将此表达式的第一组解释为编码名称。如果Python未知编码,则在编译期间会引发错误。包含编码声明的行上不得有任何Python语句。如果第一行匹配,则第二行将被忽略。
为了帮助诸如Windows之类的平台,该平台在Unicode文件的开头添加了Unicode BOM标记,UTF-8签名 \ xef \ xbb \ xbf也将被解释为“ utf-8”编码(即使没有魔术编码注释也是如此)给出)。
如果源文件同时使用UTF-8 BOM标记签名和魔术编码注释,则注释的唯一允许编码为'utf-8'。任何其他编码都会导致错误。
例子
以下是一些示例,用于阐明在Python源文件顶部定义源代码编码的不同样式:
-
使用解释器二进制文件并使用Emacs样式文件编码注释:
<span style="color:#444444">#!/ usr / bin / python #-*-编码:latin-1-*- 导入操作系统 ... #!/ usr / bin / python #-*-编码:iso-8859-15-*- 导入操作系统 ... #!/ usr / bin / python #-*-编码:ascii-*- 导入操作系统 ... </span>
-
没有解释器行,使用纯文本:
<span style="color:#444444">#此Python文件使用以下编码:utf-8 导入操作系统 ... </span>
-
文本编辑器可能以不同的方式定义文件的编码,例如:
<span style="color:#444444">#!/ usr / local / bin / python #编码:latin-1 导入操作系统 ... </span>
-
没有编码注释,Python的解析器将采用ASCII文本:
<span style="color:#444444">#!/ usr / local / bin / python 导入操作系统 ... </span>
-
编码无效的注释:
-
缺少“ coding:”前缀:
<span style="color:#444444">#!/ usr / local / bin / python #latin-1 导入操作系统 ... </span>
-
不在第1行或第2行上编码注释
<span style="color:#444444">#!/ usr / local / bin / python # #-*-编码:latin-1-*- 导入操作系统 ... </span>
-
不支持的编码:
<span style="color:#444444">#!/ usr / local / bin / python #-*-编码:utf-42-*- 导入操作系统 ... </span>
-
概念
PEP基于以下概念,必须实现这些概念才能使用这种魔术注释:
-
完整的Python源文件应使用单一编码。不允许嵌入不同编码的数据,并且在编译Python源代码期间会导致解码错误。
允许以上述方式处理前两行的任何编码都可以用作源代码编码,其中包括ASCII兼容编码以及某些多字节编码,例如Shift_JIS。它不包括对所有字符使用两个或多个字节的编码,例如UTF-16。这样做的原因是使令牌检测器中的编码检测算法保持简单。
-
转义序列的处理应该像现在一样继续工作,但是使用所有可能的源代码编码,即标准字符串文字(8位和Unicode)都可以进行转义序列扩展,而原始字符串文字仅扩展很小的子集转义序列。
-
Python的tokenizer / compiler组合将需要更新以按以下方式工作:
- 读取文件
- 假设每文件固定编码,将其解码为Unicode
- 将其转换为UTF-8字节字符串
- 标记化UTF-8内容
- 进行编译,根据给定的Unicode数据创建Unicode对象,并根据Unicode文字数据创建字符串对象,方法是先使用给定的文件编码将UTF-8数据重新编码为8位字符串数据
请注意,Python标识符仅限于编码的ASCII子集,因此在步骤4之后无需进一步转换。
实作
为了与现有代码向后兼容,该代码当前在字符串文字中使用非ASCII且未声明编码,因此将分两个阶段介绍该实现:
-
通过内部将缺少的编码声明视为“ iso-8859-1”声明,允许字符串文字和注释中使用非ASCII。这将导致任意字节字符串在处理的步骤2和步骤5之间正确地往返,并为包含非ASCII字节的Unicode文字提供与Python 2.2的兼容性。
如果在输入中发现非ASCII字节,则会对每个不正确编码的输入文件发送一次警告。
-
删除警告,并将默认编码更改为“ ascii”。
内置的compile() API将得到增强,以接受Unicode作为输入。如上所述,8位字符串输入必须经过编码检测的标准过程。
如果将带有编码声明的Unicode字符串传递给compile(),则会引发SyntaxError。
范围
该PEP旨在提供从当前(或多或少)未定义的源代码编码情况到更健壮和可移植的定义的升级路径。
历史
- 1.10及更高版本:请参阅CVS历史记录
- 1.8:添加了“。” 到编码RE。
- 1.7:在第1阶段实施中添加了警告。将Latin-1默认编码替换为解释程序的默认编码。添加了对compile()的调整。
- 1.4-1.6:细微调整
- 1.3:Martin v。Loewis的注释工作:UTF-8 BOM标记检测,Emacs样式魔术注释,两阶段实施方法
版权
该文档已放置在公共领域。
来源:https : //github.com/python/peps/blob/master/pep-0263.txt