偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.
全部博文(1750)
分类: Android平台
2013-02-03 15:24:54
因此,做类似的事情,却需要参考两个不同来源的表格,这就是吊诡之处了。事实上 repertoire map 是 glibc 独有的设计,目的是希望将 ``字集'' 与 ``字集编码方式'' 分开,这在其它 UNIX 系统下是见不到的。而根据 glibc 的作者 Ulrich Drepper 的说法,目前的目标是先将 repertoire map 发展完整,让整个 cwtype.h 字符分类系统可以动起来,未来也许会将 repertoire map 与 gconv 合并,也许就只留下 gconv 而已,而 repertoire map 就取消了。
简单说, mb/wb函数从当前locale中找到charset的名字, 调用iconv函数,
iconv先读进/usr/lib/gconv/gconv-modules, 根据charset的名字找到
应该用的module (.so), 然后装上该module, 由其作真正的转换.
但不论未来的发展如何,我们先前所谈的所有 ISO C89 与 XPG2 标准都不会变的,故我们在发展相关程序时,只要谨守这些标准,不论走到那都可以适用,甚至移植到其它的 UNIX 系统也是一样,当然前提是它们要有提供这些标准的支持。而这里可能变量较大的是 iconv 的部分,因为不同的系统间所能提供的支持程度可能会有相当大的差异。而我们的建议是,由于 UCS2 (Unicode)、UCS4、UTF8 等编码系统已经渐渐被大部分的 UNIX 系统所支持,严然成为标准的一部分,故我们应该可以很放心地使用 iconv 接口做某字集与 UCS2 等编码系统的转换,而且在某些情况下使用 iconv 也是必须的。但如果要做两个交集呈度不高的编码系统互转 (如 Big5 与 GB2312 之间) 时,也许还是稍微保守一些,由我们自己在程序里做转换表格会较为适当。
1. wchar_t 实际上是用 4 个 bytes 来储存一个 UCS-4 编码的字符设计的(glibc 里面)。
实际 ISO C 标准并没有强制要求这样(允许定义成 char 保持和 char 的一致)。于是 glibc
里面的 wchar_t 可以表示出 ISO 10646 标准下所有字符。实际 locale 里面多见的是 utf-8,
这是一种兼容 ASCII 的变长编码标准(非 ASCII 字符使用 2-6 个 bytes)完全编码了 ISO 10646 下
所有字符。今后,将仅仅鼓励使用 utf-8 标准进行外部编码。似乎这样看来,一个程序使用
utf-8 编码就能解决所有的语言问题了... 但是,这不是真的。
2. 注意到很多 char array 的函数返回 int,为了保持一致 wchar_t array 返回 wint_t。wchar_t 的范围
是 WCHAR_MIN 和 WCHAR_MAX 两个 macro 声明的。WEOF 是 wchar_t 的 eof 版本。
MB_LEN_MAX 表示所有 locale 里面 multi-byte 字符最多需要编码字节,而 MB_CUR_LEN_MAX 是
当前的 locale 下最长的,前者是一个常数,后者是一个运行时决定的数字(写程序时候必须注意)。
这些声明一部分在 limits.h 一部分在 stdlib.h。
有些字符集包含了一类带有状态编码的字符,如很多 Latin 语言系带有的 accent,通常用一个
编码表示一种 accent,后面一个字符表示需要添加 accent 的字符(因此如果需要输出 accent 本身,
后面还得加另外一个字符,比如空格)。这种字符就是表示进入到某种状态,常用 mbstate_t 类型描述,
一些函数需要利用这种信息(wchar.h)。可用 mbsinit() 测试是否处于读入新字符状态。
wint_t btowc( int c )将常规 char 转换成为 wchar_t,转换规则由 LC_CTYPE 决定。失败返回 WEOF。反过来是 wctob()。
size_t mbrtowc (wchar_t *restrict pwc, const char *restrict s, size_t n, mbstate_t *restrict ps)将 multi-byte 字符转换成 wchar_t,其中就要用到 mbstate_t 了。反过来是 wcrtomb()。
size_t mbrlen (const char *restrict s, size_t n, mbstate_t *ps)求 multi-byte 字符串长。字符串的转换使用
size_t mbsrtowcs (wchar_t *restrict dst, const char **restrict src, size_t len, mbstate_t *restrict ps)反过来是 wcsrtombs()。这个函数也有 +n 版本,就是 mbsnrtowcs() 和 wcsnrtombs()。
iconv_t iconv_open (const char *tocode, const char *fromcode)建立一个转换,再使用
size_t iconv (iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)转换,最后
int iconv_close (iconv_t cd)关闭掉。注意不同线程之间不能共享这个 iconv_t 的 descriptor。这些在 iconv.h 中给出了定义。
char * setlocale (int category, const char *locale)第一个参数可以用定义过的宏,如 LC_ALL 等等,后面的试设置的类型,用一个字符串表示,
struct lconv * localeconv (void)它返回了一个 struct lconv,我们不能对此进行修改。但是可以利用该结构里面的一些信息来格式化我们需要
char * nl_langinfo (nl_item item)与前者不同,这里主要利用 nl_item 返回对应项的内容,我们知道 strftime() 函数可以输出格式化的
size_t strftime (char *s, size_t max, const char *format, const struct tm *tm)我们可以如下利用该函数
strftime (s, len, nl_langinfo (D_T_FMT), tp);这样把不同 locale 下的输出搞定,下面的程序为我们展示了不同 locale 下时间格式输出不同的可能:
#include程序输出如下:#include #include #include void showTime( const char *locale, struct tm *t ) ; int main( int argc, char *argv[] ) { time_t t = time( NULL ) ; struct tm *curtime = localtime( &t ) ; showTime( "C", curtime ) ; showTime( "en_US", curtime ) ; showTime( "en_GB", curtime ) ; showTime( "zh_CN.utf-8", curtime ) ; return 0 ; } void showTime( const char *locale, struct tm *t ) { const int len = 100 ; char buff[ len ] ; // Show current locale setlocale( LC_ALL, locale ) ; printf( "Current locale is %s, here is strftime() result:\n", setlocale( LC_ALL, NULL ) ) ; strftime( buff, len, nl_langinfo( D_T_FMT ), t ) ; puts( buff ) ; }
Current locale is C, here is strftime() result: Sun Nov 19 21:55:54 2006 Current locale is en_US, here is strftime() result: Sun 19 Nov 2006 09:55:54 PM CST Current locale is en_GB, here is strftime() result: Sun 19 Nov 2006 21:55:54 CST Current locale is zh_CN.utf-8, here is strftime() result: 2006年11月19日 星期日 21时55分54秒没想到中文也可以正常输出,太赞了!类似于 strftime(),另有一个函数用于格式化数值和货币
#include程序输出如下#include #include #include void show_number( const char *locale ) ; int main( int argc, char *argv[] ) { show_number( "C" ) ; show_number( "en_US" ) ; show_number( "en_GB" ) ; show_number( "zh_CN.utf-8" ) ; return 0 ; } void show_number( const char *locale ) { const int len = 300 ; char buff[ len ] ; // Show current locale setlocale( LC_ALL, locale ) ; printf( "Current locale is %s, here is strfmon() result:\n", setlocale( LC_ALL, NULL ) ) ; strfmon( buff, len, "%=*+20#5n%=*+20#5n\n%=*+20#5i%=*+20#5i", 123.45, -567.89, 12345678.9, -0.123456 ) ; puts( buff ) ; }
Current locale is C, here is strfmon() result: **123.45 -**567.89 12345678.90 -****0.12 Current locale is en_US, here is strfmon() result: $***123.45 -$***567.89 USD 12,345,678.90 -USD *****0.12 Current locale is zh_CN.utf-8, here is strfmon() result: ¥***123.45 ¥-***567.89 CNY12,345,678.90 CNY-*****0.12英文的(en_GB 删掉了,里面有非法字符 -.-b)
int rpmatch (const char *response)返回 1 表示是,0 表示不是,-1 表示两个都不是 -.-b 可以简单的验证一下该东东对不对
#include这是交互过程:#include #include void is_a_duck( const char *locale ) ; int main( int argc, char *argv[] ) { is_a_duck( "C" ) ; is_a_duck( "en_US" ) ; is_a_duck( "zh_CN.utf-8" ) ; return 0 ; } void is_a_duck( const char *locale ) { char *line ; size_t len ; // Show current locale setlocale( LC_ALL, locale ) ; line = NULL ; len = 0 ; printf( "Current locale is %s. Are you a duck? ", setlocale( LC_ALL, NULL ) ) ; while( getline( &line, &len, stdin ) >= 0 ) { /* Check the response. */ int res = rpmatch( line ) ; if (res >= 0) { /* We got a definitive answer. */ if( res > 0 ) puts( "Yeah, you are a duck!" ) ; else puts( "Then why you resembles a duck so much?!" ) ; break; } } /* Free what getline allocated. */ free( line ) ; }
Current locale is C. Are you a duck? hhh no Then why you resembles a duck so much?! Current locale is en_US. Are you a duck? yes Yeah, you are a duck! Current locale is zh_CN.utf-8. Are you a duck? 你管我是不是 是 Yeah, you are a duck!汗,有段程序从 libc 的 manual 里面 copy 出来改了改...