首页 > 代码库 > linux系统字符编码详解

linux系统字符编码详解

    众所周知,地球上的语言多种多样,在计算机世界,自然也是要适应各种语言.我们安装各种系统的时候也是明示了要选择语言环境和支持的语言环境.

    而linux系统的字符编码设置尤为复杂,这可能也是没有考虑到非技术人员去研究这些东西吧.

    我遇到的事情是这样的,我们使用了docker,但是docker容器里的语言环境经常莫名错乱,搞得很头痛,所以偶尔就要切换,或者生成其他字符集.所以现在假设我们需要切换一个中文语言环境,而切换了之后是乱码的,也就是没用的.

基本上,乱码的原因就是没加载到合适的字符编码环境,即使是显示到下面这样的,其实也未必是加载到,只是证明这些变量更改成功而已.

#查看环境变量
vim /etc/profile
export LANG=zh_CN.UTF-8
export LANGUAGE=zh_CN.UTF-8
export LC_TIME=zh_CN.UTF-8
#加载一下
source /etc/profile
#看一下加载成功没
locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME=zh_CN.UTF-8
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

还要看看locale -a有没有加载到系统上,

locale -a
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
C
POSIX
en_US.utf8

大家看到了,系统上根本就没有zh_CN.UTF-8的字符编码,所以即使改了,也是没有任何意义,所以你看到的还是会出现乱码.


要解决这个问题,就要我们对linux字符编码有比较透彻的理解.

首先,我们要看看我们的系统有哪些可支持的语言,都存在大名鼎鼎的i18n里面,

#系统支持的语言环境
ll /usr/share/i18n/locales/
aa_DJ        ar_LY        ber_DZ      ca_FR       de_LU@euro  en_IN  es_EC       eu_ES       fur_IT          hi_IN               it_CH             kw_GB   ml_IN         nl_BE       POSIX             sid_ET       sv_FI@euro  translit_circle        tt_RU@iqtelif   yi_US
aa_ER        ar_MA        ber_MA      ca_IT       doi_IN      en_NG  es_ES       eu_ES@euro  fy_DE           hne_IN              it_IT             ky_KG   mni_IN        nl_BE@euro  ps_AF             si_LK        sv_SE       translit_cjk_compat    ug_CN           yo_NG
aa_ER@saaho  ar_OM        bg_BG       crh_UA      dv_MV       en_NZ  es_ES@euro  fa_IR       fy_NL           hr_HR               it_IT@euro        lb_LU   mn_MN         nl_NL       pt_BR             sk_SK        sw_KE       translit_cjk_variants  uk_UA           yue_HK
aa_ET        ar_QA        bho_IN      csb_PL      dz_BT       en_PH  es_GT       ff_SN       ga_IE           hsb_DE              iu_CA             lg_UG   mr_IN         nl_NL@euro  pt_PT             sl_SI        sw_TZ       translit_combining     unm_US          zh_CN
af_ZA        ar_SA        bn_BD       cs_CZ       el_CY       en_SG  es_HN       fi_FI       ga_IE@euro      ht_HT               iw_IL             li_BE   ms_MY         nn_NO       pt_PT@euro        so_DJ        szl_PL      translit_compat        ur_IN           zh_HK
am_ET        ar_SD        bn_IN       cv_RU       el_GR       en_US  es_MX       fi_FI@euro  gd_GB           hu_HU               ja_JP             lij_IT  mt_MT         nr_ZA       ro_RO             so_ET        ta_IN       translit_font          ur_PK           zh_SG
an_ES        ar_SY        bo_CN       cy_GB       el_GR@euro  en_ZA  es_NI       fil_PH      gez_ER          hy_AM               ka_GE             li_NL   my_MM         nso_ZA      ru_RU             so_KE        ta_LK       translit_fraction      uz_UZ           zh_TW
ar_AE        ar_TN        bo_IN       da_DK       en_AG       en_ZM  es_PA       fo_FO       gez_ER@abegede  i18n                kk_KZ             lo_LA   nan_TW@latin  oc_FR       ru_UA             so_SO        te_IN       translit_hangul        uz_UZ@cyrillic  zu_ZA
ar_BH        ar_YE        br_FR       de_AT       en_AU       en_ZW  es_PE       fr_BE       gez_ET          ia_FR               kl_GL             lt_LT   nb_NO         om_ET       rw_RW             sq_AL        tg_TJ       translit_narrow        ve_ZA
ar_DZ        as_IN        br_FR@euro  de_AT@euro  en_BW       es_AR  es_PR       fr_BE@euro  gez_ET@abegede  id_ID               km_KH             lv_LV   nds_DE        om_KE       sa_IN             sq_MK        th_TH       translit_neutral       vi_VN
ar_EG        ast_ES       brx_IN      de_BE       en_CA       es_BO  es_PY       fr_CA       gl_ES           ig_NG               kn_IN             mag_IN  nds_NL        or_IN       sat_IN            sr_ME        ti_ER       translit_small         wa_BE
ar_IN        ayc_PE       bs_BA       de_BE@euro  en_DK       es_CL  es_SV       fr_CH       gl_ES@euro      ik_CA               kok_IN            mai_IN  ne_NP         os_RU       sc_IT             sr_RS        ti_ET       translit_wide          wa_BE@euro
ar_IQ        az_AZ        byn_ER      de_CH       en_GB       es_CO  es_US       fr_FR       gu_IN           is_IS               ko_KR             mg_MG   nhn_MX        pa_IN       sd_IN             sr_RS@latin  tig_ER      tr_CY                  wae_CH
ar_JO        be_BY        ca_AD       de_DE       en_HK       es_CR  es_UY       fr_FR@euro  gv_GB           iso14651_t1         ks_IN             mhr_RU  niu_NU        pap_AN      sd_IN@devanagari  ss_ZA        tk_TM       tr_TR                  wal_ET
ar_KW        be_BY@latin  ca_ES       de_DE@euro  en_IE       es_CU  es_VE       fr_LU       ha_NG           iso14651_t1_common  ks_IN@devanagari  mi_NZ   niu_NZ        pa_PK       se_NO             st_ZA        tl_PH       ts_ZA                  wo_SN
ar_LB        bem_ZM       ca_ES@euro  de_LU       en_IE@euro  es_DO  et_EE       fr_LU@euro  he_IL           iso14651_t1_pinyin  ku_TR             mk_MK   nl_AW         pl_PL       shs_CA            sv_FI        tn_ZA       tt_RU                  xh_ZA
#语言确实博大精深,不过我们直奔主题,我们需要的只是中文,只要看到这个就足够了
zh_CN

假如没有怎么办,也确实是有可能的,那我们就需要安装了

#ubuntu安装
apt-get -y install language-pack-zh-hans language-pack-zh-hans-base
#centos安装
yum install kde-l10n-Chinese
yum reinstall glibc-common

如果是一般的物理机,或者kvm/vmware的虚拟机,到了这一步,然后再source一遍,一般也能解决的了,然鹅,我的docker还是不行,真是ri了狗.

不过,就算他没有,我们也可以自己造一个啊,听起来很玄乎,但是真的可以,利用localedef命令来做

---------------------------------------------------

先看看这个命令的介绍:

localedef 命令

用途

转化语言环境和字符集描述(charmap)源文件以生成语言环境数据库。

语法

localedef [ -c ] [ -f Charmap ] [ -i SourceFile ] [ -L LinkOptions ] [ -m MethodFile ] LocaleName

参数

-c    就算发出了警告消息,仍然强制语言环境表的创建。
-f CharMap    指定包含了字符符号映射以及将元素符号整理为实际字符编码的文件名称。一个语言环境与且仅与一个代码集关联。如果没有指定该标志,那么采用 ISO 8859-1 代码集。注:完全支持系统提供的某些 CharMap 文件。然而,当用户提供的正确定义的 CharMap 文件可能正常工作时,仍不能保证这样使用的结果。
-i SourceFile    指定包含语言环境类别源定义的文件的路径名。如果没有给出此标志,那么源定义从标准输入上读取。
-L LinkOptions    将指定的链接选项发送给构建语言环境的 ld 命令。
-m MethodFile    指定描述构造语言环境时覆盖的方法的方法文件的名称。方法文件指定用户提供的覆盖现有定义的子例程以及包含指定的子例程的库的路径名。当构造语言环境对象的时候,localedef 命令读取方法文件并使用入口点。指定的代码集方法也可用来分析由 CharMap 变量指向的文件。注:要创建 64 位语言环境,方法文件必须将库的路径指定为具有包含指定的子例程的两个共享对象(一个 32 位,另一个 64 位)的单一压缩文档。对 32 位和 64 位共享对象指定不同的路径导致 localedef 命令由于不兼容 XCOFF 格式而失败。
LocaleName    指定要创建的语言环境名称。它是后来可以用于访问此语言环境信息的名称。

----------------------------------------------------------

看完介绍,也确定有这个语言支持,那就来造一个吧

#造一个中文的utf-8字符编码,
#意思就是指定zh_CN的语言环境,然后指定UTF-8编码,命名为zh_CN.UTF-8
localedef -i zh_CN -f UTF-8 zh_CN.UTF-8
#在看看系统有没有这个字符编码没有,
locale -a
C
POSIX
zh_CN.utf8
#可以看到存在了,在加载一下
source  /etc/profile

然后,一切都回归正常,不再乱码了.

linux系统字符编码详解