首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Linux字符集、编码、转码、字体相关知识

Linux字符集、编码、转码、字体相关知识

作者头像
YaoQi
发布2025-07-14 18:58:27
发布2025-07-14 18:58:27
24400
代码可运行
举报
运行总次数:0
代码可运行

今天是2025年元旦,祝大家新年快乐!

元,初始的意思;旦,日出、白天的意思。元旦就是一年的第一天。

字符集

字符集,就是把一批字符排个序放到一个表格中。比如ASCII(英文字母数子标点符号等)、GBK(汉字)、Unicode(统一的字符编码,包括世界上所有字符)。字符集只是一个集合,是后边字符的存储,转换,显示设计的基本依据。操作系统中并不必须存储一套字符集,这只是一个逻辑概念。

字符编号编码

有了字符集,就考虑制定编号编码规范,用来存储,传输字符。编码规范定义了用多少字节保存字符,以及字符编码和字符数子ID的对应关系。操作系统只有知道如何编码和解码才能操作字符。

制定字符编码首先要按字符集大小,确定字符ID编号范围。比如ASCII用一个字节即可,ID范围0x00-0xFF就够用了,而GBK使用两个字节ID范围0x0000-0xFFFF,Unicode使用4个字节ID范围0x00000000-0xFFFFFFFF。

一般字符数多的字符集,不会连续编号,会分区,比如Unicode把ID范围分成多个平面,每个平面编码0x0000-0xFFFF范围的字符,用的最多的是第0平面即0x00000000-0x0000FFFF,中文在0x4E00-0x9FFF范围的CJK区域。

然后是对字符进行编码,这个编码用于存储和传输字符。

有的字符编码直接使用字符集中字符的数子ID进行编码,比如ASCII和扩展ASCII,直接使用8位一字节,保存一个字符的数子ID。字符‘A’的ID为65,编码为0x41。我们学C语言时直接把数字存入char变量中就是因为这一对应的编码特性。

又比如中文GBK字符集采用单字节双字节编码一个字符,也是直接存储数字ID。编码中,前128个编码都是单字节编码,范围0x00-0x7F,与ASCII相对应。汉字采用双字节编码,比如“我”在GBK中编号为52946,保存为16进制0xCED2。

再比如Unicode,编码方式都有很多种,有定长编码比如UTF-32,使用固定4个字节编码一个字符。也有变长编码比如UTF-8,编码长度从1到4个字节。UTF-8单字节编码,范围0x00-0x7F也是和ASCII对应。汉字“我”在Unicode中编号ID为25105(0x6211)UTF-8编码却为0xE68891 占3个字节,UTF-32编码为0x11620000(小端序)。

实际看下“我”的三个编码:

注:

1. 图中0x0a是换行符,0xfffe0000是utf-32的前导BOM用来说明后边是什么编码,什么字节序。

2. 以上文本文件是用iconv命令进行编码转换得到的,见后文。

3. 所以文件大小并不能直接反应字符数量,需要看什么编码。

字体

字体用来定义字符如何在显示设备上显示,显示设备比如显示器,打印机等。字体文件中,需要为字符集数子ID,指定其显示方式。

显示方式就是字体的格式,有点阵字体,轮廓字体等,具体不展开了,总之就是决定了字符要显示的图形。

小结

由以上知识可知,操作系统要显示一个字符,首先系统要支持某个字符集,读取文件或其他输入设备(图形界面一般可以认为“输入法”是个输入设备,把原始的键盘击键转)的内容后,按字符编码规则进行解码得到字符ID,然后查找对应的字体,按ID找到要显示的图形(或图形的显示轮廓)最后进行显示。

如果一个操作系统要能处理显示多种字符集,需要安装多个字符集的编解码规则和多个字符集的字体,但这样就比较复杂了。

现代操作系统会选择一种字符集作为处理字符的标准,也就是被称作操作系统内码的东西,早期内码也就是ASCII,现在自然会使用Unicode了其他编码的字符集都要转码成内码,然后按内码查找字体显示就行了。

以下内容,基于Ubuntu系统

查看当前系统区域和字符集配置

locale命令

代码语言:javascript
代码运行次数:0
运行
复制
root@qc:~# locale
LANG=en_HK.UTF-8
LANGUAGE=en_HK:en
LC_CTYPE="en_HK.UTF-8"
LC_NUMERIC="en_HK.UTF-8"
LC_TIME="en_HK.UTF-8"
LC_COLLATE="en_HK.UTF-8"
LC_MONETARY="en_HK.UTF-8"
LC_MESSAGES="en_HK.UTF-8"
LC_PAPER="en_HK.UTF-8"
LC_NAME="en_HK.UTF-8"
LC_ADDRESS="en_HK.UTF-8"
LC_TELEPHONE="en_HK.UTF-8"
LC_MEASUREMENT="en_HK.UTF-8"
LC_IDENTIFICATION="en_HK.UTF-8"
LC_ALL=

这是一组环境变量。指示了应用程序也应该使用的字符集,当前语言和地区,时间数字等的显示格式等。

en_HK.UTF-8 : en是指英文,HK指香港地区,UTF-8指使用的字符集。

修改环境变量即可修改应用程序所用字符集

代码语言:javascript
代码运行次数:0
运行
复制
临时修改(当前终端生效):
export LANG="zh_CN.UTF-8"

永久修改:
echo "export LANG="zh_CN.UTF-8"  >> /etc/proflile
source /etc/profile

区域用于让程序界面显示你能看得懂的字符和格式。

字符集用来指定编解码字符默认的方式。

因此地域设置不正确不要影响对字符文件的处理,关键是字符集。

查看当前可配置的地域和字符集

locale -a

代码语言:javascript
代码运行次数:0
运行
复制
root@qc:~# locale -a
C
C.UTF-8
en_HK.utf8
en_US.utf8
POSIX

注:以上命令出现了C和POSIX做下说明。

C语言环境:C 语言环境通常表示“标准C”语言环境,使用默认的、本地化无关的设置。这意味着字符分类、字符串排序、数字格式等遵循POSIX(便携操作系统接口)标准,而不考虑任何特定的语言或区域设置。

POSIX语言环境:POSIX 和 C 基本上是同义词,两者在本地化方面的行为完全一致。POSIX标准定义了操作系统和应用程序的接口,包括本地化方面的规则。

添加支持的地域和字符集

只有系统支持的才能添加进去

cat /usr/share/i18n/SUPPORTED 检查支持的地域语言

vim /etc/locale.gen 取消想添加的语言地区行前的注释,比如zh_CN.UTF-8

执行 locale-gen 命令,生成区域编码信息

locale-gen是个shell脚本,感兴趣的朋友可以分析下其逻辑。简单来说就是会根据 /usr/share/i18n/locales/ 中本地化相关数据和字符编码,调用localedef命令创建一个zh_CN.UTF-8这样的组合配置,更新 /usr/lib/locale/locale-archive文件,如果使用--no-archive参数执行,则每种语言环境会有一个单独的子目录:

代码语言:javascript
代码运行次数:0
运行
复制
root@hole:~# vim /etc/locale.gen 
root@hole:~# locale-gen  --no-archive
Generating locales (this might take a while)...
  en_US.UTF-8... done
  zh_CN.UTF-8... done
Generation complete.
root@hole:~# ls /usr/lib/locale/
C.UTF-8  en_US.utf8  zh_CN.utf8
root@hole:~# ls /usr/lib/locale/zh_CN.utf8/
LC_ADDRESS  LC_CTYPE           LC_MEASUREMENT  LC_MONETARY  LC_NUMERIC  LC_TELEPHONE
LC_COLLATE  LC_IDENTIFICATION  LC_MESSAGES     LC_NAME      LC_PAPER    LC_TIME

这时就可以通过locale -a 看到新的locales设置了,然后可以这样启用它:

代码语言:javascript
代码运行次数:0
运行
复制
localectl set-locale LANG=zh_CN.UTF-8

注:

1.在 /usr/share/locale 中的每个目录都包含特定语言的程序消息,用于不同地区的显示,这些文件来自软件包iso-codes。

2. /etc/locale.alias 用于定义本地化名称的别名,配置时可以用别名。

字符编码转换

/usr/share/i18n/charmaps/ 目录用于存储字符映射表(character maps),这些映射表定义了不同字符集的编码方式之间的映射,一般是和内码Unicode进行映射。

比如上文提到的“我”字,在GBK映射中对应的是其Unicode ID 6211:

代码语言:javascript
代码运行次数:0
运行
复制
root@hole:~# zcat /usr/share/i18n/charmaps/GBK.gz | grep U6211
<U6211>     /xce/xd2     <CJK>
root@hole:~#

每个字符集都映射到了Unicode,然后是不是就可以通过这个映射,以Unicode为中心进行相互转换了。当前前提是两个字符集里都有对应的字符。

可以使用file命令简单查看一个文本文件的字符编码

代码语言:javascript
代码运行次数:0
运行
复制
root@hole:~# file UTF-8.txt 
UTF-8.txt: UTF-8 Unicode text
root@hole:~# file GBK.txt 
GBK.txt: ISO-8859 text
root@hole:~# file UTF-32.txt 
UTF-32.txt: Unicode text, UTF-32, little-endian

用iconv命令进行文件编码转换:

代码语言:javascript
代码运行次数:0
运行
复制
iconv -f 源编码 -t 目标编码 源文件  > 目标文件
iconv -l 列出支持的字符编码

root@hole:~# iconv -f utf-8 -t gbk UTF-8.txt > GBK.txt
root@hole:~# iconv -f utf-8 -t ascii UTF-8.txt > ascii.txt
iconv: illegal input sequence at position 0
# 把汉字转码成ASCII,失败了

用convmv进行文件名的编码转换

一般需要安装下 apt install convmv

代码语言:javascript
代码运行次数:0
运行
复制
convmv -f 原编码 -t 新编码 --notest  文件名
convmv -f 原编码 -t 新编码 --notest  -r 目录名
convmv --list 显示支持的字符集
--notest 意为直接修改,否则默认只会显示它会做什么。建议先不加,确认后再加。

注:地域配置和编码转换来自locales软件包,没有相关的路径时可以考虑安装下。

字体

字符只有被显示设备显示成一个符号我们才能看到它,关于一个字符显示的高矮胖瘦就由字体决定了。

/etc/fonts/fonts.conf 为字体配置文件。

在Linux系统中,字体文件通常存储在以下几个主要路径中:

系统字体路径:

/usr/share/fonts/:这是系统字体的主要存储路径,包含了预安装的系统字体。

/usr/local/share/fonts/:用于存储由系统管理员或用户手动安装的字体。

用户字体路径:

~/.fonts/:这是用户级别的字体路径,存储了当前用户安装的字体。在较新的系统中,通常会使用以下路径:

~/.local/share/fonts/:用户安装的字体存储路径,推荐在较新的系统中使用。

这些路径中包含了各种格式的字体文件,如 TrueType 字体(.ttf)、OpenType 字体(.otf)、Bitmap 字体(.pcf)等。

字体配置工具fontconfig

代码语言:javascript
代码运行次数:0
运行
复制
apt install fontconfig
fc-list #列出系统中的字体文件,字体名,字形
fc-match --sort  #和list差不多,但是不带字体路径
fc-cache -v #更新缓存,安装新字体后需要执行

安装字体

可以手动下载字体文件,放到字体路径下,然后执行 fc-cache命令。

有些字体可以通过软件源安装,比如安装Microsoft字体:

代码语言:javascript
代码运行次数:0
运行
复制
apt install ttf-mscorefonts-installer

控制台字体

控制台字体位于/usr/share/consolefonts/ 下,目录中的文件通常是字体文件,文件扩展名一般为 .psf 或 .psfu。这些文件定义了字符的像素图形表示,用于在控制台中显示文本。

配置控制台字体:

代码语言:javascript
代码运行次数:0
运行
复制
setfont /usr/share/consolefonts/Lat15-Fixed16.psfu.gz

关于代码页(Code Pages)

Windows代码页,比如我们最长见的CP936(代表中国 - 简体中文(GB2312)),就是字符编码在Windows上的一种表示方法,Linux并没有此概念。

关于远程终端

我们用Putty等终端模拟器远程连接到服务器,远程程序比如bash、vim等会按环境变量处理其字符编码和转码,然后发送到本地的虚拟终端,其显示字符的编码和字体需要跟随远程主机配置下,当然现在一般配置成UTF-8就行了,字体当然按喜好,程序员或技术人员首选等宽字体。

关于vim

vim 是支持自动编码识别和转换的,在 vimrc 中配置即可,

/etc/vimrc是系统级配置, ~/.vimrc是用户级配置,甚至当前工作路径也可以单独配置。

代码语言:javascript
代码运行次数:0
运行
复制
set encoding=utf-8
set fileencodings=ucs-bom,utf-8,gbk,cp936,gb2312,gb18030,big5,euc-jp,euc-kr,latin1

fileencodings指定探测文件编码的顺序,encoding指vim使用的编码,文件中的编码会转码后显示和编辑,保存的时候还是会按原始编码保存。

要想直接在vim中转码也可以:

代码语言:javascript
代码运行次数:0
运行
复制
# 以下在vim中执行
:set fileencoding   查看当前文件编码
:set fileencoding=utf-8  转换文件编码为utf-8
:set fileformat 查看文件换行符格式
:set fileformat=unix 转换文件格式,可以是unix、dos、mac

具体编码的识别和转换也是依赖操作系统的(安装locals包),否则vim该乱码还是乱码。

关于输入法

输入法(Input Method)输出的字符编码取决于操作系统和应用程序的设置,现代计算机系统中,输入法通常使用Unicode作为字符编码。

Windows系统中的输入法一般使用Unicode编码,特别是在处理多语言和复杂字符集时。输入法框架(如Text Services Framework,TSF)会将用户输入的字符转换为Unicode,并将其传递给应用程序。

在Linux系统中,输入法框架(如IBus、fcitx)也通常使用Unicode编码。

输入法引擎将用户输入的字符转换为Unicode码点,并将其传递给目标应用程序。

macOS系统中的输入法(如内置的拼音输入法)同样使用Unicode编码。

系统会将用户输入的字符转换为Unicode,并在应用程序中显示。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 漫跑的小兔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档