Linux 字符集
Linux 字符集(character set,charset),字符编码。
字符集和字符编码
在 Linux 系统中,字符编码和字符集是处理文本数据(包括文件名、文件内容、终端显示、环境变量等)的核心概念。理解它们对于避免乱码、正确进行国际化(i18n)和本地化(l10n)至关重要。
字符集
(Charater Set)是字符的集合。字符是各种文字和符号的总称,包括文字、标点符号、图形符号、数字、控制符号等。常见的字符集,如:
- ASCII字符集:最基本的字符集,包含 128 个字符(0-127),包括英文字母、数字、标点符号和控制字符。每个字符用 1 个字节(7 位)表示。
- ISO-8859 系列 (Latin-1, Latin-2 等): 扩展 ASCII 的字符集,使用 1 个字节(8 位),增加了 128 个字符,用于支持西欧、中欧、北欧等语言的字母和符号。范围是 0-255。
- Unicode字符集:现代标准! 旨在包含世界上所有书写系统的所有字符。它定义了一个巨大的字符集(码位空间),远远超出了 1 字节或 2 字节的范围。Unicode 本身不是编码。
字符码
(Code Point)也称编码点,在每个字符集中,每个字符有个编号,称之为字符集编号,该编号就是字符码。Code point(code point or code position is any of the numerical values that make up the code space,该字符在子库表中的位置)。譬如,ASCII字符集中字母’A’的字符码就是65。
字符编码
(Character Encoding)是字符的编码方式,是将字符集中的字符码
映射为字节流的一种具体实现方案。或者说,是将字符集中的字符映射到计算机存储(字节序列)的规则。如:
- ASCII 编码: 直接对应 ASCII 字符集,1 字节/字符。
- ISO-8859-X 编码: 直接对应各自的 ISO-8859-X 字符集,1 字节/字符。
- UTF-8:Linux 和 Web 的绝对主流!Unicode 的一种变长编码方案。
- 使用 1 到 4 个字节表示一个字符。
- 完全兼容 ASCII: ASCII 字符(0-127)用 1 个字节表示,且编码值与 ASCII 相同。这是其巨大优势。
- 非 ASCII 字符(如中文、日文、表情符号)使用 2、3 或 4 个字节。
- 优点:节省空间(对于主要使用 ASCII 的文本),无字节序问题,兼容性好。
- UTF-16:Unicode 的另一种编码。使用 2 或 4 个字节表示一个字符。存在大端序(BE)和小端序(LE)的问题。在 Linux 桌面/服务器环境中不如 UTF-8 常见,但在 Windows 和 Java 内部使用较多。
- UTF-32:Unicode 编码,固定使用 4 个字节表示每个字符。非常浪费空间,主要用于内部处理,很少用于存储或传输。
- GB2312 / GBK / GB18030:主要用于简体中文的字符集和编码(GB18030 兼容 Unicode)。
- Big5: 主要用于繁体中文的字符集和编码。
- EUC-JP / Shift_JIS:主要用于日文的编码。
字符集和字符编码是完全不同的概念。字符编码依赖于字符集,没有字符集,字符编码就无意义,也就是说字符集是字符编码的基础。一个字符集可以有多个编码实现,所以有众多的字符编码方式。对于ASCII、GB2312、Big5、GBK,其既是字符集,本身又是字符编码方式,所以会让人很混乱。
查看系统支持的字符集
1
cat /usr/share/i18n/SUPPORTED
locale
Linux 使用 locale
系统来定义用户的语言、地域、字符编码偏好等环境设置。这是配置字符编码的关键。
locale
是某一个地域内的人们的语言习惯、文化传统和生活习惯,是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境
。
locale命令
查看已安装的字符集
1
locale -a
- zh是指中文、汉语
- en是指英语
- 中国大陆zh_CN
- 香港zh_HK
- 台湾zh_TW
- 新加坡zh_SG
查看已安装的中文字符集
1
2
# 只查看中国大陆,不包括香港、台湾
locale -a|grep zh_CN
环境变量
LANG
:设置默认的 locale,是其他未设置的 LC_*
变量的后备值,优先级最低。
LANGUAGE
:是设置应用程序的界面语言。
LC_ALL
:最高优先级,覆盖所有其他 LC_*
变量和 LANG
。通常用于临时强制某个 locale。
LC_CTYPE
:最关键! 决定字符的分类(字母、数字、空格等)、大小写转换规则以及文本数据和文件名的字符编码。例如:
en_US.UTF-8
(英语, 美国, UTF-8 编码)zh_CN.GB18030
(简体中文, 中国, GB18030 编码)zh_TW.UTF-8
(繁体中文, 台湾, UTF-8 编码)ja_JP.UTF-8
(日语, 日本, UTF-8 编码)
其他 LC_*
变量 (LC_MESSAGES
, LC_TIME
, LC_NUMERIC
, LC_MONETARY
, LC_COLLATE
) 控制消息语言、日期时间格式、数字/货币格式、排序规则等。
设置 locale
系统级:通常通过 /etc/locale.conf
(systemd 系统) 或 /etc/default/locale
(某些 sysvinit 系统) 设置 LANG
。
用户级:在 ~/.bashrc
, ~/.profile
, ~/.config/i18n
等 shell 配置文件中设置 LANG
或 LC_*
变量。例如:
1
2
3
export LANG="en_US.UTF-8"
# 或者更精确地控制字符编码
export LC_CTYPE="en_US.UTF-8"
临时:在命令行中设置 LC_ALL
或 LC_CTYPE
:
1
LC_ALL="zh_CN.GBK" some_command # 仅对这次命令生效
终端模拟器 (Terminal Emulator)
即使系统 LC_CTYPE
设置正确,终端模拟器(如 GNOME Terminal, Konsole, xterm, PuTTY)本身也有自己的字符编码设置。
终端的编码设置必须与它接收到的数据的编码(通常由 LC_CTYPE
决定)以及它使用的字体所能显示的字符集匹配,才能正确显示文本,避免乱码。
在终端的设置菜单中通常可以找到字符编码选项(如 UTF-8, GBK, ISO-8859-1 等)。现代 Linux 发行版的终端通常默认设置为 UTF-8。
文件编码
文本文件本身是以特定的字节序列存储的,这个序列遵循某种字符编码规则。
Linux 工具本身通常不关心文件的扩展名(.txt
, .c
等),它们依赖 LC_CTYPE
的设置来解释文件的字节流。
如果文件的编码与 LC_CTYPE
设置的编码不一致,或者终端编码不匹配,就会导致文件内容显示为乱码。
重要工具
iconv
iconv
:强大的字符编码转换工具。
语法:iconv -f from_encoding -t to_encoding inputfile -o outputfile
示例:将 GBK 文件转换为 UTF-8
1
iconv -f GBK -t UTF-8 gbkfile.txt -o utf8file.txt
file
file
:猜测文件的类型和可能的编码(基于内容分析,不一定完全准确)。
1
file -i filename.txt # 输出如:filename.txt: text/plain; charset=utf-8
enca / chardetect
enca
/ chardetect
:更智能的文件编码分析工具(通常需要额外安装)。
文本编辑器
文本编辑器:大多数现代编辑器(Vim, Emacs, VS Code, Gedit, Kate, Nano 等)都可以检测或指定文件的编码进行打开、编辑和保存。这是处理不同编码文件最常用的方式。
locale-gen
locale-gen
:生成系统可用的 locale(通常由发行版安装程序或管理员运行)。
修改字符集
旧版 Debian 和 Ubuntu
/var/lib/locales/supported.d/
目录是旧版 Debian 和 Ubuntu(主要在使用 dpkg-reconfigure locales
管理 locale 的时代)用来存放用户自定义 locale 支持列表的地方。每个文件对应一种语言环境列表。
1
ls /var/lib/locales/supported.d/
/var/lib/locales/supported.d/
目录下有两个文件e
n和zh-hans
(网上说en和zh-hans是由local文件分割成的两个文件)。
en
保存英文字符。
zh-hans
表示简体中文,保存中文字符。
修改(添加或删除)汉语(中文)字符集
1
sudo vim /var/lib/locales/supported.d/zh-hans
例如:
1
2
zh_CN.UTF-8 UTF-8
zh_SG.UTF-8 UTF-8
现代Linux发行版
在现代 Linux 发行版中,特别是使用 systemd
的系统(如 Debian 10+/Ubuntu 16.04+/Fedora/RHEL 8+ 等),/var/lib/locales/supported.d/
这个目录已经不存在了。
现在发生了什么变化?
集中化管理 (/etc/locale.gen
):
- 现代系统将所有可生成 locale 的列表统一放在一个文件:
/etc/locale.gen
。 - 这个文件包含了系统上所有可能生成的 locale,但大部分行默认是被注释掉的(以
#
开头)。 - 你需要编辑这个文件,取消注释你需要的 locale(比如
en_US.UTF-8 UTF-8
,zh_CN.UTF-8 UTF-8
等),然后运行生成命令
。
生成命令 (locale-gen
):
- 编辑好
/etc/locale.gen
后,你需要运行sudo locale-gen
(不需要任何参数)。 - 这个命令会读取
/etc/locale.gen
中所有未被注释的行,并实际生成这些 locale 定义文件(存放在/usr/lib/locale/
目录下)。 - 运行
locale-gen
之后,新启用的 locale 就可以在locale -a
命令中看到,并可以在LANG
,LC_*
环境变量中使用了。
localectl
命令 (systemd 系统):
- 在基于
systemd
的系统上,还有一个更高级的管理工具:localectl
。 - 你可以用它来查看和设置系统范围的默认 locale:
localectl list-locales
:列出系统已经生成的可用 locale(相当于locale -a
)。localectl set-locale LANG=en_US.UTF-8
:设置系统默认的LANG
环境变量,这会修改/etc/locale.conf
文件。注意:这设置的是环境变量,并不会生成新的 locale。你需要的 locale 必须先通过/etc/locale.gen
+locale-gen
生成出来。
- 它通常不直接管理 locale 的生成,生成工作还是由
/etc/locale.gen
+locale-gen
负责。
安装中文字符集(旧版)
- 安装中文包
1
apt-get install language-pack-zh*
- 配置相关环境变量
1 2 3 4
vim /etc/environment # 通常应该不是使用这一个文件;使用以下文件之一 vim /etc/locale.conf vim /etc/default/locale vim ~/.bashrc
增加2行:
1 2
LANG="zh_CN.UTF-8" # 这一行不一定需要 LANGUAGE="zh_CN:zh:en_US:en" # 这一行不一定需要
不一定需要增加,不增加中文仍然乱码的话,才增加上面1行 或 2行。
- 重新设置本地配置
1
dpkg-reconfigure locales
安装中文字符集(现代化)
- 安装中文包
1
apt-get install language-pack-zh*
- 修改字符集,编辑
/etc/locale.gen
取消相关注释1 2 3 4 5
# 编辑 sudo vim /etc/locale.gen # 取消注释 en_US.UTF-8 UTF-8 zh_CN.UTF-8 UTF-8
- 运行生成命令
1
sudo locale-gen
- 重启 或 注销。