本来是修改自己一个终端小程序的宽字符处理,然后就和编码纠结上了。

这两天花了不少时间继续研究了下这块,越研究越让人迷糊,还存在不少疑问。只能说在研究和总结这块时,我的内心是崩溃的……希望以后不再在这块纠结。

以下总结在环境 Linux,Python2.7 下研究。

先谈谈终端下中文字符(宽字符)的对齐输出问题:

终端下中文字符(宽字符)的对齐输出问题

比如我在终端下输出表格,里面包含了中英文,因为中英文的长度不一致,len()获取的宽度是编码字节的长度,不是实际长度:

>>> len(u'我'.encode('utf-8'))

3

>>> len(u'我'.encode('gbk'))

2

这里「我」如果是 utf-8 编码,则占 3 个字节长度,而在 gbk 下则是 2 个字节长度。所以通过len()来固定长度显然不合适,造成无法对齐的情况。

后来看到这个帖子,了解到unicodedata这个库,因为最终的 unicode 码点是唯一的,所以通过这个库,可以获取某个 unicode 字符的宽度。

我的处理:

#coding: utf-8

import unicodedata

def wide_chars(s):

"""return the extra width for wide characters

ref: http://stackoverflow.com/a/23320535/1276501"""

if isinstance(s, str):

s = s.decode('utf-8')

return sum(unicodedata.east_asian_width(x) in ('F', 'W') for x in s)

# example

max_width = 20

s1 = u'中文'

# Format Specification Mini-Language

# ref: https://docs.python.org/2/library/string.html#format-specification-mini-language

fmt_str1 = u'{0:<%s}|' % (max_width - wide_chars(s1))

s2 = u'ab'

fmt_str2 = u'{0:<%s}|' % (max_width - wide_chars(s2))

s3 = u'新年快乐'

fmt_str3 = u'{0:<%s}|' % (max_width - wide_chars(s3))

print(fmt_str1.format(s1))

print(fmt_str2.format(s2))

print(fmt_str3.format(s3))

F表示宽字符,如¥;W表示其它的字符,如中文汉字和符号。具体看 EAST ASIAN WIDTH

(注:先前以为宽字符都是全角字符,不过发现半角中文逗号也是属于 F,懒得研究这块了)

上面函数返回的是一个 unicode 字符串中,所有中文字符的个数,因为大部分中文字符在 utf-8 下是占三个字节,而宽度是两个字符,所以减去中文个数就是字节和宽度一样。注意这里是用的 unicode 字符串,如果在 Python2.x 下使用 str,则需要改为 + wide_chars()。

当然上面还不是很严谨,因为没有具体研究哪些字符可能不是 3 个字节。Python 中计算字符宽度 这篇文章里提到了另外一种方案。不过目前使用来说,上面的例子已经足够了。

然后就是开始字符编码的各种风暴了……

Terminal Emulator Character Encoding and $LANG

比如 Mac 下我使用的 Terminal 是 iTerm2, 终端的字符编码设置在Profiles -> Terminal -> Character Encoding,选择的是Unicode (UTF-8)。

$LANG设置是zh_CN.UTF-8, zh_CN 表示语言,即这里的中文,UTF-8 也就是编码集。终端显示的一些结果,如ls, date的输出、vim 的提示都是中文。

locale 相关

关于locale输出各字段的含义,在man 7 locale中有解释。

对于区域设置,有两个特殊的:C 和 POSIX。

比如查看 mac 手册时,因为字符集原因,呈现的是乱码,这时经常会使用LANG=C man xxx,意思就是去掉本地化,使用程序自身的语言去呈现,当然一般就是英文了。

关于 locale 的字段,比较常用的是LC_ALL, LANG, LC_CTYPE, LC_TIME等:

LC_ALL 用于最高优先级的全局设置,一般为空;为空时会寻找相应字段LC_*的值,如果这个也没设置,就找默认的LANG值。

LC_CTYPE 用于字节序列编码的解释,即字符显示等作用

LC_TIME 时间的显示格式和本地化

参考:

再说 Python Source Code Encodings

这个的作用就是让 Python 解释器在读文件时,对里面的非 ascii 字符做编解码处理。

比如最常用的:

coding=utf-8

如果设置其它的字符集,如 gb2312:

coding=gb2312

则要求文件的编码是 gb2312,否则比如保存为 utf-8 编码,则以 gb2312 编码去读取文件会导致错误。

另外就是执行的输出,比如:

#coding=gb2312

a = "中文"

print(a)

print(a.decode('gb2312').encode('gb2312'))

需要设置终端编码是 gb2312,否则输出是乱码。

Python sys.getdefaultencoding()

Python 2.x 下,默认是 ascii,这个与系统环境无关。

#coding=utf-8

import sys

reload(sys)

sys.setdefaultencoding('utf-8')

print sys.getdefaultencoding()

a = '中文' + u'abc'

如果不改变默认编码为 utf-8,则报错:

UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe4 in position 0: ordinal not in range(128)

因为这个字符串拼接的实际效果是:

a = '中文'.decode(sys.getdefaultencoding()) + u'abc'

In vim, encoding vs fileencoding vs fileencodings

注意 fileencoding 和 fileencodings 区别,一个是单数,一个是复数。

encoding:字符串。影响 buffer, register 等,就是在输入字符时最后呈现的样子。默认是”latin1” or value from $LANG

fileencoding:字符串。新建文件写文件时的字符编码。如果没设置则和encoding一样,否则在写文件时会做转码;读取文件时,会被fileencodings设置。

fileencodings:列表。当准备编辑一个已存在的文件时,vim 尝试使用第一个字符编码去读取文件,如果出错则使用第二个。

即:

读文件:从 fileencoding 转换到 encoding

写文件:从 encoding 转换到 fileencoding

所以在打开或保存时可以看到converted的标记。

举个例子:

set encoding=utf-8

set fileencoding=gb2312

set fileencodings=utf-8,gb2312

新建一个文件,vim 显示的编码使用 utf-8,在输入中文后,保存会看到左下角提示converted,命令行通过file -i filename可以看到文件字符集为 charset=iso-8859-1。再次打开文件时,通过 fileencodings 来设置 fileencoding,并进行转码到 encoding 设置。

延伸阅读:

另外有个疑问 TODO:

如果我的 encoding 和 fileencoding 都设置的 gb2312,而终端设置的 UTF-8 时,实际保存的是 utf-8;如果终端是 gb2312,则保存的是 gb2312。

而如果 encoding 是 utf-8, fileencoding 是 gb2312, 终端是 UTF-8 时,实际保存的是 gb2312

这块目前还不清楚原因,只能猜测是因为终端字符集和 encoding buffer 这块有关,虽然设置的 gb2312,但是实际是终端的 utf-8,但是因为和 fileencoding 一样设置的 gb2312,所以不做转码。

总结一下

万能的 UTF-8 大法好

不要设置不一致,从终端到程序配置都统一为 UTF-8

其它参考

python中文对齐_Python 终端下中文字符对齐处理和编码续相关推荐

  1. python支持中文吗_Python中使用中文

    这个问题曾在我初学Python的时候令我头疼不已,尤其是目前我们因为各种包的原因还只能使用2.x的版本.在3.x中字符编码已经统一用Unicode了. Python 默认支持的是ASCII字符,包含了 ...

  2. 终端下中文乱码解决方法

    1.在终端下输入 vim ~/.zshrc 2.在文件内容末端添加: export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8 转载于:https://www ...

  3. python表格对齐_python str.format 中文对齐的细节问题,

    python str.format 中文对齐的细节问题, 写了一个练手的爬虫...在输出的时候出现了让人很不愉♂悦的问题 像这样: 令人十分难受啊! #------------------------ ...

  4. python关键字中文意思_python解析URL中文关键字

    搜索引擎或者APP搜索时,其实生成的http链接中基本都带有UTF8或者其他编码的中文关键字,目前只做了UTF8的,其他编码可以通过字符范围筛选. 以下为解析方法: import urllib imp ...

  5. python汉字排序_Python实现针对中文排序的方法

    本文实例讲述了Python实现针对中文排序的方法.分享给大家供大家参考,具体如下: Python比较字符串大小时,根据的是ord函数得到的编码值.基于它的排序函数sort可以很容易为数字和英文字母排序 ...

  6. python显示汉字_python如何显示中文字体

    python如何显示中文字体? 在这里,你可以选择2种不同的解决方法 方法一:定义声明好编码格式 首先你要做的,是在打开写入文件时,声明encoding编码put_in = open(becopyed ...

  7. python乱码怎么办_python中输出中文乱码怎么解决

    我们在使用python进行编程的时候,往往会面临输出中文的问题,这个时候往往会报错,小编这次与大家分享一下怎么解决. 工具/原料 Pycharm 方法/步骤 1 我们以pycharm为IDE工具,来举 ...

  8. python翻译中文读法_Python如何将中文翻译成拼音?,又,一个,奇葩,要求,是,转,的...

    这年头什么样子的需求都会出现,下面这张图就是很好的体现了.这就是说为啥要你学学Python啦!保不准你的领导会有各种奇葩需求,对于像Python这样的"万金油"编程语言来说,简直不 ...

  9. 基于python文本挖掘实战_python实现CNN中文文本分类

    [实例简介] CNN 中文文本挖掘 文本分类 python 深度学习 机器学习 [实例截图] [核心代码] zh_cnn_text_classify-master └── zh_cnn_text_cl ...

最新文章

  1. GetListToJson
  2. a标签 vue 动态点击_vue实现a标签点击高亮方法
  3. RPM 包相关命令详解
  4. kotlin学习之类的扩展(四)
  5. 2019 秦皇岛 I - Invoker Gym - 102361I dp
  6. 环形队列出队的元素怎么输出出来_队列:队列在线程池等有限资源池中的应用...
  7. Python机器学习:评价分类结果008ROC曲线
  8. mysql 字段唯一效率_对于同一个字段使用唯一性索引和非唯一性索引,效率有区别吗???...
  9. 红米AirDots无线蓝牙耳机连接win10笔记本
  10. BackTrack4 官方指南
  11. 怎样将PDF转成表格?超赞的两种PDF转Excel方法
  12. python爬虫怎么保存图片_使用Python爬虫怎么将网页图片保存到本地
  13. cvc 降噪_此降噪非彼降噪,你要的是哪种降噪?
  14. 算法提高 盾神与条状项链
  15. UCN(User-Centric Networks,用户中心网络)
  16. 微服架构基础设施环境平台搭建 -(四)在Kubernetes集群基础上搭建Kubesphere平台
  17. 张亚勤:微软九成研发资源投入云计算
  18. C++每日一课(八)
  19. 安装neurokit 的艰难历程
  20. android shape 无边框颜色,Android 使用shape定义不同控件的的颜色、背景色、边框色...

热门文章

  1. (专升本)Word(格式化表格操作)
  2. linux 修改无损分区大小,CentOS 7.6无损调整分区大小
  3. CString的截取字符串函数,如Mid、Left和Right
  4. 《智慧城市智慧多功能杆服务功能与运行管理规范》
  5. Android10系统开发实现跳过开机向导、插电源线不休眠等默认配置
  6. 苹果 M1 芯片预示着 RISC-V 完全替代 ARM?
  7. 傻妞对接青龙,对接QQ、TG、微信。一键、DOCKER安装----JD挂机一体化平台搭建之篇三【2022.11.29】
  8. oracle if中过程判断,oracle的if判断语句
  9. 外交教你用连词 Unit 2
  10. Centos系统临时修改时间、永久修改时间