#include
char* setlocale (int category, const char* locale); // 区域设置(本地设置、地域设置)函数
struct lconv* localeconv (void); // 返回区域设置中与数字和货币有关的信息
struct lconv; //包含了与数字和货币有关的区域设置信息的结构体
区域设置是与某个地区(或者说某个国家)的语言和文化相关的一系列内容,包含日期格式、数字格式、货币格式(例如货币符号、国际货币代码)、字符处理(例如字符分类)、字符比较(字符排序)等多个方面,其中数字和货币信息还包含了很多细节,为了便于管理,C语言将这些细节信息组织成一个结构体,它的名字就是 struct lconv。
也就是说,struct lconv 是一个包含了与数字和货币有关的区域设置信息的结构体。
localeconv() 函数会返回一个 struct lconv 类型的指针,从而让用户了解与数字和货币有关的地域信息,这也是获取 struct lconv 的唯一途径。
struct lconv
{
/* Numeric (non-monetary) information. */
char *decimal_point; /* Decimal point character. */
char *thousands_sep; /* Thousands separator. */
/* Each element is the number of digits in each group;
elements with higher indices are farther left.
An element with value CHAR_MAX means that no further grouping is done.
An element with value 0 means that the previous element is used
for all groups farther left. */
char *grouping;
/* Monetary information. */
/* First three chars are a currency symbol from ISO 4217.
Fourth char is the separator. Fifth char is '\0'. */
char *int_curr_symbol;
char *currency_symbol; /* Local currency symbol. */
char *mon_decimal_point; /* Decimal point character. */
char *mon_thousands_sep; /* Thousands separator. */
char *mon_grouping; /* Like `grouping' element (above). */
char *positive_sign; /* Sign for positive values. */
char *negative_sign; /* Sign for negative values. */
char int_frac_digits; /* Int'l fractional digits. */
char frac_digits; /* Local fractional digits. */
/* 1 if currency_symbol precedes a positive value, 0 if succeeds. */
char p_cs_precedes;
/* 1 iff a space separates currency_symbol from a positive value. */
char p_sep_by_space;
/* 1 if currency_symbol precedes a negative value, 0 if succeeds. */
char n_cs_precedes;
/* 1 iff a space separates currency_symbol from a negative value. */
char n_sep_by_space;
/* Positive and negative sign positions:
0 Parentheses surround the quantity and currency_symbol.
1 The sign string precedes the quantity and currency_symbol.
2 The sign string follows the quantity and currency_symbol.
3 The sign string immediately precedes the currency_symbol.
4 The sign string immediately follows the currency_symbol. */
char p_sign_posn;
char n_sign_posn;
#ifdef __USE_ISOC99
/* 1 if int_curr_symbol precedes a positive value, 0 if succeeds. */
char int_p_cs_precedes;
/* 1 iff a space separates int_curr_symbol from a positive value. */
char int_p_sep_by_space;
/* 1 if int_curr_symbol precedes a negative value, 0 if succeeds. */
char int_n_cs_precedes;
/* 1 iff a space separates int_curr_symbol from a negative value. */
char int_n_sep_by_space;
/* Positive and negative sign positions:
0 Parentheses surround the quantity and int_curr_symbol.
1 The sign string precedes the quantity and int_curr_symbol.
2 The sign string follows the quantity and int_curr_symbol.
3 The sign string immediately precedes the int_curr_symbol.
4 The sign string immediately follows the int_curr_symbol. */
char int_p_sign_posn;
char int_n_sign_posn;
#else
char __int_p_cs_precedes;
char __int_p_sep_by_space;
char __int_n_cs_precedes;
char __int_n_sep_by_space;
char __int_p_sign_posn;
char __int_n_sign_posn;
#endif
};
struct lconv 包含了如下的成员变量(不分先后顺序):
成员变量 | 类型 | 地域设置为"C" 时的值 |
说明 |
---|---|---|---|
decimal_point | char* | “.” | 非货币数字的小数点,例如 100.25。 我们通常认为小数点就是点号 . ,在任何语言文化中都是固定的;其实不然,在法语、南非语、丹麦语、德语、希腊语、部分西班牙语中,小数点是逗号, 。 |
thousands_sep | char* | “” | 非货币数字的千位分隔符,例如 12,172,390,000。 千位分隔符其实就是数字中的逗号。依西方的习惯,人们在数字中加入一个符号,以免因数字位数太多而难以看出它的值。所以人们在数字中,每隔三位数加入一个逗号,也就是千位分隔符,以便更加容易认出数值。 |
grouping | char* | “” | 千位分隔符 thousands_sep 分隔非货币数字时,每一个分组包含的数字个数。 我们通常认为,每隔三位数加入一个千位分隔符(例如 12,172,390,000),但是这并不是固定的,也可以每隔两位数加入一个千位分隔符(例如 1,21,72,39,00,00),或者最开始的三位数加入一个分隔符,以后每隔两位数加入一个分隔符(例如12,17,23,90,000),或者是其他情况。grouping 成员就用来指定每隔几位加入一个千位分隔符。 grouping 包含一组以 \ 为前导符的数字,每一个数字表示插入千位分隔符的位数,例如:
按照从左到右的顺序看 grouping 包含的数字,它们依次指明了从右到左(从低位到高位)插入千位分隔符的位置,这两者的顺序恰好是相反的。如果数字的位数过多,那么按照 grouping 最右边的数字(结束标志 \0 前面的数字)插入千位分隔符。如果 grouping 包含了值为 CHAR_MAX 的数字,那么表示没有进一步的分组。 |
int_curr_symbol | char* | “” | 国际货币符号(国际货币代码)。 国际货币符号由三个字母组成,遵循 ISO-4217 标准,例如,美元的国际符号是 "USD" ,欧元的国际符号是"GBP" ,人民币的国际符号是"CNY" 。
注意,国际货币符号后面还会紧跟一个空格,用于分隔国际货币符号和货币量,例如 USD 29.86。最终,int_curr_symbol 由四个字符组成。 |
currency_symbol | char* | “” | 本地货币符号。 适用于当前区域设置的当地流通的货币符号,例如,美元的货币符号为 $ ,欧元的货币符号为€ ,人民币的货币符号为¥ 。 |
mon_decimal_point | char* | “” | 货币量(表示货币的数字)的小数点,例如 ¥ 25.5。 mon_decimal_point 针对货币量,而 decimal_point 针对非货币量。 |
mon_thousands_sep | char* | “” | 货币量的千位分隔符,例如 ¥ 25,000。 mon_thousands_sep 针对货币量,而 thousands_sep 针对非货币量。 |
mon_grouping | char* | “” | 千位分隔符 mon_decimal_point 分隔货币量时,每一个分组包含的数字个数,细节请参考 grouping。 mon_grouping 针对货币量,而 grouping 针对非货币量。 |
positive_sign | char* | “” | 用于表示非负(正数或者零)货币量的符号,一般为空字符串。 |
negative_sign | char* | “” | 用于表示负的货币量的符号,一般为- ,也就是负号。 |
frac_digits | char | CHAR_MAX | 在当前的区域设置中(针对当地的货币格式),货币量的小数部分保留的位数,或者说货币量的小数点右侧的数字个数。 |
p_cs_precedes | char | CHAR_MAX | 货币符号 currency_symbol 是否位于非负(正数或者零)货币量之前。例如,$ 26.3 就是货币符号位于货币量之前,26.3 $ 就是货币符号位于货币量之后。如果 p_cs_precedes 的值为 1,那么表示货币符号位于非负货币量之前;如果 p_cs_precedes 的值为 0,那么表示货币符号位于非负货币量之后。 |
n_cs_precedes | char | CHAR_MAX | 货币符号 currency_symbol 是否位于负(正数或者零)的货币量之前。例如,$ -26.3 就是货币符号位于货币量之前,-26.3 $ 就是货币符号位于货币量之后。如果 n_cs_precedes 的值为 1,那么表示货币符号位于负的货币量之前;如果 n_cs_precedes 的值为 0,那么表示货币符号位于负的货币量之后。 |
p_sep_by_space | char | CHAR_MAX | 货币符号 currency_symbol 与非负(正说或者零)货币量之间是否有空格。空格用来分隔货币符号和货币量,让货币的格式更加美观。 如果 p_sep_by_space 的值为 1,那么表示货币符号与非负货币量之间有空格;如果 p_sep_by_space 的值为 0,那么表示货币符号与非负货币量之间没有空格。 |
n_sep_by_space | char | CHAR_MAX | 货币符号 currency_symbol 与负的货币量之间是否有空格。空格用来分隔货币符号和货币量,让货币的格式更加美观。 如果 n_sep_by_space 的值为 1,那么表示货币符号与负的货币量之间有空格;如果 n_sep_by_space 的值为 0,那么表示货币符号与负的货币量之间没有空格。 |
n_sign_posn | char | CHAR_MAX | 负的货币量中 negative_sign 的位置:
n_sign_posn 为 CHAR_MAX 表示未定义。 |
p_sign_posn | char | CHAR_MAX | 非负(正数或者零)货币量中 positive_sign 的位置,请参照 n_sign_posn。 |
int_frac_digits | char | CHAR_MAX | 和 frac_digits 类似。不过 frac_digits 针对的是当地(当前区域设置)的货币格式,而 int_frac_digits 针对的是国际货币格式。 |
int_p_cs_precedes | char | CHAR_MAX | 和 p_cs_precedes 类似。不过 p_cs_precedes 针对的是当地(当前区域设置)的货币格式,而 int_p_cs_precedes 针对的是国际货币格式。 |
int_n_cs_precedes | char | CHAR_MAX | 和 n_cs_precedes 类似。不过 n_cs_precedes 针对的是当地(当前区域设置)的货币格式,而 int_n_cs_precedes 针对的是国际货币格式。 |
int_p_sep_by_space | char | CHAR_MAX | 和 p_sep_by_space 类似。不过 p_sep_by_space 针对的是当地(当前区域设置)的货币格式,而 int_p_sep_by_space 针对的是国际货币格式。 |
int_n_sep_by_space | char | CHAR_MAX | 和 n_sep_by_space 类似。不过 n_sep_by_space 针对的是当地(当前区域设置)的货币格式,而 int_n_sep_by_space 针对的是国际货币格式。 |
int_p_sign_posn | char | CHAR_MAX | 和 p_sign_posn 类似。不过 p_sign_posn 针对的是当地(当前区域设置)的货币格式,而 int_p_sign_posn 针对的是国际货币格式。 |
int_n_sign_posn | char | CHAR_MAX | 和 n_sign_posn 类似。不过 n_sign_posn 针对的是当地(当前区域设置)的货币格式,而 int_n_sign_posn 针对的是国际货币格式。 |
""
,或者 char 类型的成员变量的值为 CHAR_MAX
,那么表示(在当前的区域设置中)该成员变量的值不可用(无效)。
int_p
和 int_n
开头的成员变量(最后六个)是 C99 标准新加入的,请确认您的编译器是否支持。
下表给出了依照当地习惯对货币量$-3.00
格式化的各种方式,它们由 struct lconv 中的三个成员的值决定,分别是 n_sep_by_space、n_sign_posn 和 n_cs_precedes。
n_sep_by_space: 0 | |||||
---|---|---|---|---|---|
n_sign_posn | 0 | 1 | 2 | 3 | 4 |
n_cs_precedes: 0 | (3.00$) | -3.00$ | 3.00$- | 3.00-$ | 3.00$- |
n_cs_precedes: 1 | ($3.00) | -$3.00 | $3.00- | -$3.00 | $-3.00 |
n_sep_by_space: 1 | |||||
n_sign_posn | 0 | 1 | 2 | 3 | 4 |
n_cs_precedes: 0 | (3.00 $) | -3.00 $ | 3.00 $- | 3.00 -$ | 3.00 $- |
n_cs_precedes: 1 | ($ 3.00) | -$ 3.00 | $ 3.00- | -$ 3.00 | $- 3.00 |
setlocale() 函数既可以用来对当前程序进行地域设置(本地设置、区域设置),也可以用来获取当前程序的地域设置信息。
通过 setlocale() 函数进行地域设置,改变程序的语言环境。地域设置是与某个地区(或者说某个国家)的语言和文化相关的一系列内容,包含字符集(字符编码)、日期格式、数字格式、货币格式(例如货币符号、国际货币代码)、字符处理(例如字符分类)、字符比较(字符排序)等。
category
地域设置的影响范围。地域设置包含日期格式、数字格式、货币格式、字符处理、字符比较等多个方面的内容,当前的地域设置可以只影响某一方面的内容,也可以影响所有的内容,通过 category 参数就可以指明地域设置的影响范围。
category 的值不能随便设置,必须使用
宏(展开为常量) | 本地设置的影响范围 |
---|---|
LC_ALL | 影响所有内容。 |
LC_COLLATE | 影响字符比较(字符排序),具体来说就是影响 在默认的地域设置中(设置为 "C" ),比较字符大小其实比较的是字符的内码,C语言一般使用 ASCII 编码,此时比较的就是字符的 ASCII 码值;但是在其它的地域设置中,可能会有不同的比较方式,例如在中文环境下就可以按照拼音来对字符进行比较和排序。
Windows 和 Linux 都支持按拼音排序,但是 Mac OS 不支持;Windows 甚至还支持按照笔画来排序,不过需要修改“控制面板 --> 区域和语言”里面的设置。 |
LC_CTYPE | 1) 影响字符分类和字符转换,具体来说就是影响 例如,在默认的地域设置中(设置为 "C" ),只有"abc…xyzABC…XYZ" 才被认为是字母;但是在其它的地域设置中,可能会包含更多的字母,例如在中文环境下,拼音ü 、拉丁文àáâãäåçö 、希腊文σωδψφ (数学物理公式中常用希腊字母)等都将成为字母。
即使在特定的地域设置下,一个字符是否是字母还跟操作系统有关系,例如在中文环境下,罗马数字 2) 还会影响某些多字节字符和宽字符处理函数,例如 mbtowc()、mbstowcs() 等。
不过在实际测试中,暂时未发现这些函数会受到 LC_CTYPE 的影响。LC_CTYPE 的影响范围最大,可以说是地域设置中最重要的一项内容。 |
LC_MONETARY | 影响货币信息,包括货币符号、国际货币代码等;货币信息可以从 localeconv() 返回的 lconv 结构体中取得。 例如,美元的货币符号是 $ ,国际代码是USD ;人民币的货币符号是¥ ,国际代码是CNY ;英镑的货币符号是£ ,国际代码是GBP 。 |
LC_NUMERIC | 影响数字格式,包括小数点(用哪个字符来表示小数点)、数字分组等。 世界上大部分地区都使用 . 表示小数点,例如 12.45、0.88 等;但是在法语地区却使用, 表示小数点,此时printf("%f", 12.45); 的输出结果就是12,450000。 |
LC_TIME | 影响日期时间的格式,具体来说就是影响 strftime() 函数的行为。 例如,美国地区书写日期的格式是 月/日/年 ,比如08/31/2017 ;而大陆地区书写日期的格式是年/月/日 ,比如2017/08/31 。 |
locale
地域设置的名称(字符串),也就是设置为哪种地域,或者说哪种语言文化。
对于不同的平台和不同的编译器,地域设置的名称可能会不同,C语言标准没有干预太多。C语言标准只是规定,各个组织在实现编译器时至少要支持以下三个名称:
地域设置名称 | 说明 |
---|---|
“C” | 默认的地域设置,C语言程序启动时就使用"C" 地域设置,也就是相当于调用setlocale(LC_ALL,“C”) 。"C" 是一种非常中立的地域设置,不偏向于任何一个地区,它会尽量少地包含地域设置信息,这些信息只是让C语言程序能够正常运行。大多数情况下,"C" 仅仅是对小数点进行了设置(设置为. ),其它的信息都被置空。 |
“” | 使用当前操作系统默认的地域设置。这点很容易理解,如果操作系统是英文版的,那就使用英文环境,如果操作系统是中文版的,那就使用中文环境,这样做提高了C程序的兼容性,可以根据操作系统的版本自动地选择语言。
并不是所有的编译器都能很好的支持 |
NULL | 不指定任何名称。此时 setlocale() 不会对地域设置进行任何修改,仅仅是返回当前地域设置的名称。换句话说,如果我们仅仅想知道当前使用的是哪种地域设置,而不想修改它,那么就可以将 locale 参数置为 NULL。 |
除了以上三个强制要求的名称,其他名称在 Windows 和 Linux 下的写法一般不同,读者可以猛击下面的链接了解更多细节:
如果 setlocale() 执行成功,那么返回一个指向字符串的指针,该字符串包含了当前地域设置的名称。也就是说,setlocale() 会将当前地域设置的名称返回。
如果 setlocale() 执行失败(例如为 locale 指定的名称不存在,就会导致地域设置失败),那么返回空指针 NULL。
refer : linux下 locale 的格式
在 Linux 下,locale 的命名格式为:
language_area.charset
language 表示语言,例如英语或中文;area 表示使用该语言的地区,例如美国或者中国大陆;charset 表示字符集编码,例如 UTF-8 或者 GBK。举一个简单的例子:
zh_CN.UTF-8
zh 代表中文,CN 代表大陆地区,UTF-8 表示字符集编码。charset 可以省略,此时会选择当前语言的默认 charset。Linux 发行版大都使用 UTF-8 编码,它是 Unicode 字符集的一种编码方式,能够支持世界上的所有语言;省略 charset,也就意味使用 UTF-8。
locale 名称 | 说明 |
---|---|
af_ZA | 南非语 |
ar_AE | 阿拉伯语(阿联酋) |
ar_BH | 阿拉伯语(巴林) |
ar_DZ | 阿拉伯语(阿尔及利亚) |
ar_EG | 阿拉伯语(埃及) |
ar_IQ | 阿拉伯语(伊拉克) |
ar_JO | 阿拉伯语(约旦) |
ar_KW | 阿拉伯语(科威特) |
ar_LB | 阿拉伯语(黎巴嫩) |
ar_LY | 阿拉伯语(利比亚) |
ar_MA | 阿拉伯语(摩洛哥) |
ar_OM | 阿拉伯语(阿曼) |
ar_QA | 阿拉伯语(卡塔尔) |
ar_SA | 阿拉伯语(沙特阿拉伯) |
ar_SY | 阿拉伯语(叙利亚) |
ar_TN | 阿拉伯语(突尼斯) |
ar_YE | 阿拉伯语(也门) |
az_AZ | 阿塞拜疆语(拉丁文) |
az_AZ | 阿塞拜疆语(西里尔文) |
be_BY | 比利时语 |
bg_BG | 保加利亚语 |
bs_BA | 波斯尼亚语(拉丁文,波斯尼亚和黑塞哥维那) |
ca_ES | 加泰隆语 |
cs_CZ | 捷克语 |
cy_GB | 威尔士语 |
da_DK | 丹麦语 |
de_AT | 德语(奥地利) |
de_CH | 德语(瑞士) |
de_DE | 德语(德国) |
de_LI | 德语(列支敦士登) |
de_LU | 德语(卢森堡) |
dv_MV | 第维埃语 |
el_GR | 希腊语 |
en_AU | 英语(澳大利亚) |
en_BZ | 英语(伯利兹) |
en_CA | 英语(加拿大) |
en_CB | 英语(加勒比海) |
en_GB | 英语(英国) |
en_IE | 英语(爱尔兰) |
en_JM | 英语(牙买加) |
en_NZ | 英语(新西兰) |
en_PH | 英语(菲律宾) |
en_TT | 英语(特立尼达) |
en_US | 英语(美国) |
en_ZA | 英语(南非) |
en_ZW | 英语(津巴布韦) |
es_AR | 西班牙语(阿根廷) |
es_BO | 西班牙语(玻利维亚) |
es_CL | 西班牙语(智利) |
es_CO | 西班牙语(哥伦比亚) |
es_CR | 西班牙语(哥斯达黎加) |
es_DO | 西班牙语(多米尼加共和国) |
es_EC | 西班牙语(厄瓜多尔) |
es_ES | 西班牙语(传统) |
es_ES | 西班牙语(国际) |
es_GT | 西班牙语(危地马拉) |
es_HN | 西班牙语(洪都拉斯) |
es_MX | 西班牙语(墨西哥) |
es_NI | 西班牙语(尼加拉瓜) |
es_PA | 西班牙语(巴拿马) |
es_PE | 西班牙语(秘鲁) |
es_PR | 西班牙语(波多黎各(美)) |
es_PY | 西班牙语(巴拉圭) |
es_SV | 西班牙语(萨尔瓦多) |
es_UY | 西班牙语(乌拉圭) |
es_VE | 西班牙语(委内瑞拉) |
et_EE | 爱沙尼亚语 |
eu_ES | 巴士克语 |
fa_IR | 法斯语 |
fi_FI | 芬兰语 |
fo_FO | 法罗语 |
fr_BE | 法语(比利时) |
fr_CA | 法语(加拿大) |
fr_CH | 法语(瑞士) |
fr_FR | 法语(法国) |
fr_LU | 法语(卢森堡) |
fr_MC | 法语(摩纳哥) |
gl_ES | 加里西亚语 |
gu_IN | 古吉拉特语 |
he_IL | 希伯来语 |
hi_IN | 印地语 |
hr_BA | 克罗地亚语(波斯尼亚和黑塞哥维那) |
hr_HR | 克罗地亚语 |
hu_HU | 匈牙利语 |
hy_AM | 亚美尼亚语 |
id_ID | 印度尼西亚语 |
is_IS | 冰岛语 |
it_CH | 意大利语(瑞士) |
it_IT | 意大利语(意大利) |
ja_JP | 日语 |
ka_GE | 格鲁吉亚语 |
kk_KZ | 哈萨克语 |
kn_IN | 卡纳拉语 |
ko_KR | 朝鲜语 |
kok_IN | 孔卡尼语 |
ky_KG | 吉尔吉斯语(西里尔文) |
lt_LT | 立陶宛语 |
lv_LV | 拉脱维亚语 |
mi_NZ | 毛利语 |
mk_MK | 马其顿语(FYROM) |
mn_MN | 蒙古语(西里尔文) |
mr_IN | 马拉地语 |
ms_BN | 马来语(文莱达鲁萨兰) |
ms_MY | 马来语(马来西亚) |
mt_MT | 马耳他语 |
nb_NO | 挪威语(伯克梅尔)(挪威) |
nl_BE | 荷兰语(比利时) |
nl_NL | 荷兰语(荷兰) |
nn_NO | 挪威语(尼诺斯克)(挪威) |
ns_ZA | 北梭托语 |
pa_IN | 旁遮普语 |
pl_PL | 波兰语 |
pt_BR | 葡萄牙语(巴西) |
pt_PT | 葡萄牙语(葡萄牙) |
qu_BO | 克丘亚语(玻利维亚) |
qu_EC | 克丘亚语(厄瓜多尔) |
qu_PE | 克丘亚语(秘鲁) |
ro_RO | 罗马尼亚语 |
ru_RU | 俄语 |
sa_IN | 梵文 |
se_FI | 北萨摩斯语(芬兰) |
se_FI | 斯科特萨摩斯语(芬兰) |
se_FI | 伊那里萨摩斯语(芬兰) |
se_NO | 北萨摩斯语(挪威) |
se_NO | 律勒欧萨摩斯语(挪威) |
se_NO | 南萨摩斯语(挪威) |
se_SE | 北萨摩斯语(瑞典) |
se_SE | 律勒欧萨摩斯语(瑞典) |
se_SE | 南萨摩斯语(瑞典) |
sk_SK | 斯洛伐克语 |
sl_SI | 斯洛文尼亚语 |
sq_AL | 阿尔巴尼亚语 |
sr_BA | 塞尔维亚语(拉丁文,波斯尼亚和黑塞哥维那) |
sr_BA | 塞尔维亚语(西里尔文,波斯尼亚和黑塞哥维那) |
sr_SP | 塞尔维亚(拉丁) |
sr_SP | 塞尔维亚(西里尔文) |
sv_FI | 瑞典语(芬兰) |
sv_SE | 瑞典语 |
sw_KE | 斯瓦希里语 |
syr_SY | 叙利亚语 |
ta_IN | 泰米尔语 |
te_IN | 泰卢固语 |
th_TH | 泰语 |
tl_PH | 塔加路语(菲律宾) |
tn_ZA | 茨瓦纳语 |
tr_TR | 土耳其语 |
tt_RU | 鞑靼语 |
uk_UA | 乌克兰语 |
ur_PK | 乌都语 |
uz_UZ | 乌兹别克语(拉丁文) |
uz_UZ | 乌兹别克语(西里尔文) |
vi_VN | 越南语 |
xh_ZA | 班图语 |
zh_CN | 中文(简体) |
zh_HK | 中文(香港) |
zh_MO | 中文(澳门) |
zh_SG | 中文(新加坡) |
zh_TW | 中文(繁体) |
zu_ZA | 祖鲁语 |
refer: Windows 下 locale 的格式
Linux 下的 locale 只有一种格式,而 Windows 下的 locale 有三种格式。
Windows 定义了一组专有的地域设置名称供 setlocale() 使用,这些名称包含了地域设置的所有信息,例如:
setlocale ("LA_ALL", "en-US"); //en-US就是一个专有名称,它对应的是美国英语
setlocale ("LC_CTYPE", "zh-CN"); //zh-CN就是一个专有名称,它对应的是大陆汉语
使用 setlocale() 进行地域设置时,还可以按照下面的格式来设置 locale 参数:
请求设定的 locale 名可以为以下格式(参考MSDN:Language and Country/Region Strings):
locale :: “locale-name”
| “language[_country-region[.code-page]]”
| “.code-page”
| “C”
| “”
| NULL
虽然形式与 glibc 的相同,当 Windows 的 locale 名并不符合 POSIX 的规范,比如采用 GBK 字符集的大陆中文,POSIX 的名字为:zh_CN.GBK,而在 Windows CRT 中要用:Chinese_People’s Republic of China.936。
language字段的可用值参考:Language Strings
country_region 字段的可用值参考:Country/Region Strings
code_page 字段的可用值是 Windows 系统支持的代码页编号,参考:Code Page Identifiers
https://www.science.co.il/language/Locale-codes.php?s=codepage
.code_page:可以直接使用代码页来设定 locale,而且可以使用 .OCP、.ACP 两个伪代码页,.OCP 表示从系统获得的当前活动的 OEM 代码页,.ACP 表示从系统获得的活动 ANSI 代码页。
“”:根据 Windows 系统环境的活动 ANSI 代码页来设定 locale。.OCP、.ACP、和环境代码页都受控制面板中“区域与语言选项”的设置影响。默认装完简体中文版 Windows 后,活动的 ANSI 代码页为:936(即 GBK),可用chcp
控制台程序查看活动代码页。
language 表示语言,例如英语或中文;area 表示使用该语言的地区,例如美国或者中国大陆;codepage 表示代码页,例如 GBK 编码的代码页是936
。
举一个简单的例子:
chs_china.936
chs 是“chinese-simplified”的简写,表示简体中文,china 表示中国大陆,936 是 GBK 编码的代码页。可以省略 area 和 codepage,只写 language,此时会选择当前 language 的默认 area 和 codepage;如此一来,上例就可以简写为chs
。GBK 是简体中文版 Windows 默认的编码,它的代码页就是 936。
字符编码就是使用某种语言的某个地区定义的文字在计算机内部的表示方式,代码页就是字符编码在计算机中的 ID,知道了代码页也就知道使用哪个地区的哪种语言了。
使用代码页的格式为:
.codepage
例如,setlocale("LC_ALL", ".936");
就表示使用 GBK 编码,对应的是使用汉语的中国大陆地区。
例如,setlocale("LC_ALL", ".65001");
就表示使用UTF-8 编码
Windows 下可用的所有代码页列表请猛击:https://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
关于代码页使用的注意事项:
ANSI code pages can be different on different computers, or can be changed for a single computer, leading to data corruption. For the most consistent results, applications should use Unicode, such as UTF-8 or UTF-16, instead of a specific code page.
译文:
ANSI代码页可以在不同的计算机上不同,也可以针对单台计算机进行更改,从而导致数据损坏。 为了获得最一致的结果,应用程序应使用Unicode,例如UTF-8或UTF-16,而不是特定的代码页。
Linux系统查看locale的方法:在终端输入locale
windows查看代码页方法:在cmd.exe输入chcp
,或者右键cmd.exe属性查看。
修改locale:
Linux系统修改配置文件/etc/sysconfig/i18n
或/etc/sysconfig/language
Windows在开始-控制面板-区域和语言选项-选择一个语言
修改session local的方法:
windows在CMD命令行输入 mode con cp select=437
linux在终端export LANG=zh_CN.UTF8
C:\Windows\system32>mode con cp select=65001
Status for device CON:
----------------------
Lines: 300
Columns: 80
Keyboard rate: 31
Keyboard delay: 1
Code page: 65001
C:\Windows\system32>chcp
Active code page: 65001
C:\Windows\system32>
Note:
mode con cp select=65001
设置的代码页,在当前命令行有效,命令行关闭,将不再有效。Active code page: 65001
,但实际上使用时并不会生效。refer to:
Windows命令行修改代码页,显示特定国家语言
Linux与Windows编码不一致的解决方案
windows修改默认代码页
Windows的CRT中的setlocale()
以上三种格式中,第一种是微软官方推荐使用的,这种格式和 Linux 下的非常类似。