- 浏览: 30552 次
- 来自: ...
最新评论
Java中文处理学习笔记——Hello Unicode
作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com
写于:2002/07 最后更新: 09/09/2006 17:09:05
Feed Back >> (Read this before you ask question)
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://www.chedong.com/tech/hello_unicode.html
关键词:linux java mutlibyte encoding locale i18n i10n chinese ISO-8859-1 GB2312 BIG5 GBK UNICODE
内容摘要:
不知道你有没有这样的感受:为什么PHP很少有乱码问题而用Java做WEB应用却这么麻烦呢?为什么在Google上能用简体中文查到繁体中文,甚至日文的结果?而且用Google的时候发现它居然能自动根据我使用浏览器的语言选择自动调出中文界面?
很多国际化应用的让我理解了这么一个道理:Unicode是为更方便的做国际化应用设计的,而Java核心的字符是基于UNICODE的,这一机制为应用提供了对中文“字”的控制(而不是字节)。但如果不仔细理解其中的规范,这种自由反而会成为累赘,从而导致更多的乱码问题:
关于字符集的一些基本概念;
试验1:显示系统的环境设置和支持的编码方式;
试验2:系统缺省编码方式对Java应用的输入输出影响;
试验3:在WEB应用中输出和输出中的字符集问题;
关于字符集的准备知识:
ISO-8859-1 GB2312 BIG5 GBK GB18030 UNICODE 为什么会有这么多字符集编码方式?
注意:以下说明不是严格定义,一些比喻仅作为方便理解使用。
假设一个字符就是棋盘上的一个棋子,有其固定的坐标,如果需要区别所有的字符,就需要有足够的棋格容纳不同的“字符”。
英文和欧洲其他语言的单字节字符集(SingleByte Charsets):
首先对于ISO-8859系列的字符集都想象成一个:2^8 = 16 * 16 = 256个格子的棋盘,这样所有的西文字符(英文)用这样一个16×16的坐标系就基本可以覆盖全了。而英文实际上只用其中小于128(\x80)的部分就够了。利用大于128部分的空间的不同定义规则形成了真对其他欧洲语言的扩展字符集:ISO-8859-2 ISO-8859-4等……
ISO-8859-1
ISO-8859-7
其他语言
英文 其他西欧字符
ōē
英文 希腊字符
μγ
英文 其他单字节
字符集
GB2312 BIG5 SJIS等多字节字符集(MultiByte Charsets):
对于亚洲语言来说:汉字这么多,用这么一个256格的小棋盘肯定放不下,所以要区别成千上万的汉字解决办法就是用2个字节(坐标)来定位一个“字”在棋盘上的位置,将以上规则做一个扩展:
如果第1个字符是小于128(\x80)的仍和英文字符集编码方式保持兼容;
如果第1个字符是大于128(\x80)的,就当成是汉字的第1个字节,这个自己和后面紧跟的1个字节组成一个汉字;
其结果相当于在位于128以上的小棋格里每个小棋格又划分出了一个16×16的小棋盘。这样一个棋盘中的格子数(可能容纳的字符数)就变成了128 + 128 * 256。按照类似的方式有了简体中文的GB2312标准,繁体中文的BIG5字符集和日文的SJIS字符集等,GB2312字符集包含大约有六仟多个常用简体汉字。
简体中文
日文SJIS
繁体中文
英文 简
体
中
文
英文 日
文
英文
繁
体
中 文
由此可以看出,所有这些从ASCII扩展式的编码方式中:英文部分都是兼容的,但扩展部分的编码方式是不兼容的,虽然很多字在3种体系中写法一致(比如“中文”这2个字)但在相应字符集中的坐标不一致,所以GB2312编写的页面用BIG5看就变得面目全非了。而且有时候经常在浏览其他非英语国家的页面时(比如包含有德语的人名时)经常出现奇怪的汉字,其实就是扩展位的编码冲突造成的。
我把GBK和GB18030理解成一个小UNICODE:GBK字符集是GB2312的扩展(K),GBK里大约有贰万玖仟多个字符,除了保持和GB2312兼容外,繁体中文字,甚至连日文的假名字符也能显示。而GB18030-2000则是一个更复杂的字符集,采用变长字节的编码方式,能够支持更多的字符。关于汉字的编码方式比较详细的定义规范可以参考:
http://www.unihan.com.cn/cjk/ana17.htm
ASCII(英文) ==> 西欧文字 ==> 东欧字符集(俄文,希腊语等) ==> 东亚字符集(GB2312 BIG5 SJIS等)==> 扩展字符集GBK GB18030这个发展过程基本上也反映了字符集标准的发展过程,但这么随着时间的推移,尤其是互联网让跨语言的信息的交互变得越来越多的时候,太多多针对本地语言的编码标准的出现导致一个应用程序的国际化变得成本非常高。尤其是你要编写一个同时包含法文和简体中文的文档,这时候一般都会想到要是用一个通用的字符集能够显示所有语言的所有文字就好了,而且这样做应用也能够比较方便的国际化,为了达到这个目标,即使应用牺牲一些空间和程序效率也是非常值得的。UNICODE就是这样一个通用的解决方案。
UNICODE双字节字符集
所以你可以把UNICODE想象成这样:让所有的字符(包括英文)都用2个字节(2个8位)表示,这样就有了一个2^(8*2) = 256 * 256 = 65536个格子的大棋盘。在这个棋盘中,这样中(简繁)日韩(还包括越南)文字作为CJK字符集都放在一定的区位内,为了减少重复,各种语言中写法一样的字共享一个“棋格”。详细的区位见附录A
Unicode:(DoubleByte Charsets)
西 C中 其
欧 J日 它
英 K韩 语
文 言
什么还要有UTF-8?毕竟互联网70%以上的信息仍然是英文。如果连英文都用2个字节存取(UCS-2),空间浪费不就太多了?所谓UTF-8就是这样一个为了提高英文存取效率的字符集转换格式:Unicode Transformation Form 8-bit form。用UTF-8,UNICODE的2字节字符用变长个(1-3个字节)表示:
对英文,仍然和ASCII一样用1个字节表示,这个字节的值小于128(\x80);
对其他语言的用一个值位于128-256之间的字节开始,再加后面紧跟的2个字节表示,一个字符一共是3个字节;
因此,在应用中程序处理过程中所有字符都是16位(双字节),但在存取转换成字节流时使用UTF-8格式转换,对于英文字符来说和原来用ASCII方式存取时相比大小仍然是一样的,而对中文来说和原来的GB2312编码方式相比,大小为:(3字节/2字节)=1.5倍
小节:
假设英文字符集是一个16×16的棋盘,么其他语言的字符集就是把高位区重新分割的(> 128)的中等棋盘,多种字符集之间互不兼容而UNICODE本身就相当于一个256×256的大棋盘,通过一定规则将英文和其他所有语言的字符都包含在内。
试验1:操作系统语言环境设置对Java应用缺省编码方式的影响
为了了解Java应用的编码处理的机制,首先要了解操作系统对JVM缺省编码方式的影响,因此我做了一个Env.java,用于打印显示不同系统下JVM的属性和系统支持的LOCALE。程序很简单:
/* * Copyright (c) 2002 Email: chedongATbigfoot.com/chedongATchedong.com * $Id: hello_unicode.html,v 1.6 2003/11/09 07:57:11 chedong Exp $ */import java.util.*;import java.text.*;/** * 目的: * 显示环境变量和JVM的缺省属性 * 输入:无 * 输出: * 1 支持的LOCALE * 2 JVM的缺省属性 */public class Env { /** * main entrance */ public static void main(String[] args) { System.out.println("Hello, it's: " + new Date()); //print available locales Locale list[] = DateFormat.getAvailableLocales(); System.out.println("======System available locales:======== "); for (int i = 0; i < list.length; i++) { System.out.println(list[i].toString() + "\t" + list[i].getDisplayName()); } //print JVM default properties System.out.println("======System property======== "); System.getProperties().list(System.out); }}
最需要注意的是JVM的file.encoding属性,这个属性确定了JVM的缺省的编码/解码方式:从而影响应用中所有字节流==>字符流的解码方式 ,字符流==>字节流的编码方式。
LINUX下的LOCALE可以通过 LANG=zh_CN; LC_ALL=zh_CN.GBK; export LANG LC_ALL 设置。locale 命令可以显示系统当前的环境设置
Windows的LOCALE可以通过 控制面板==>区域设置 设置实现
GNU/Linux 2.4.x (J2SE1.3.1)
LANG=en_US LC_ALL=en_US GNU/Linux 2.4.x (J2SE1.3.1)
LANG=zh_CN LC_ALL=zh_CN.GBK Windows 2000(J2SE1.3.0)
区域设置:中国 中文 Windows 2000(J2SE1.3.0)
区域设置:英国 英文
Hello, it's: Tue Jul 30 11:05:44 CST 2002======System available locales:======== en Englishen_US English (United States)ar Arabicar_AE Arabic (United Arab Emirates)ar_BH Arabic (Bahrain)ar_DZ Arabic (Algeria)ar_EG Arabic (Egypt)ar_IQ Arabic (Iraq)ar_JO Arabic (Jordan)ar_KW Arabic (Kuwait)ar_LB Arabic (Lebanon)ar_LY Arabic (Libya)ar_MA Arabic (Morocco)ar_OM Arabic (Oman)ar_QA Arabic (Qatar)ar_SA Arabic (Saudi Arabia)ar_SD Arabic (Sudan)ar_SY Arabic (Syria)ar_TN Arabic (Tunisia)ar_YE Arabic (Yemen)be Byelorussianbe_BY Byelorussian (Belarus)bg Bulgarianbg_BG Bulgarian (Bulgaria)ca Catalanca_ES Catalan (Spain)ca_ES_EURO Catalan (Spain,Euro)cs Czechcs_CZ Czech (Czech Republic)da Danishda_DK Danish (Denmark)de Germande_AT German (Austria)de_AT_EURO German (Austria,Euro)de_CH German (Switzerland)de_DE German (Germany)de_DE_EURO German (Germany,Euro)de_LU German (Luxembourg)de_LU_EURO German (Luxembourg,Euro)el Greekel_GR Greek (Greece)en_AU English (Australia)en_CA English (Canada)en_GB English (United Kingdom)en_IE English (Ireland)en_IE_EURO English (Ireland,Euro)en_NZ English (New Zealand)en_ZA English (South Africa)es Spanishes_BO Spanish (Bolivia)es_AR Spanish (Argentina)es_CL Spanish (Chile)es_CO Spanish (Colombia)es_CR Spanish (Costa Rica)es_DO Spanish (Dominican Republic)es_EC Spanish (Ecuador)es_ES Spanish (Spain)es_ES_EURO Spanish (Spain,Euro)es_GT Spanish (Guatemala)es_HN Spanish (Honduras)es_MX Spanish (Mexico)es_NI Spanish (Nicaragua)et Estonianes_PA Spanish (Panama)es_PE Spanish (Peru)es_PR Spanish (Puerto Rico)es_PY Spanish (Paraguay)es_SV Spanish (El Salvador)es_UY Spanish (Uruguay)es_VE Spanish (Venezuela)et_EE Estonian (Estonia)fi Finnishfi_FI Finnish (Finland)fi_FI_EURO Finnish (Finland,Euro)fr Frenchfr_BE French (Belgium)fr_BE_EURO French (Belgium,Euro)fr_CA French (Canada)fr_CH French (Switzerland)fr_FR French (France)fr_FR_EURO French (France,Euro)fr_LU French (Luxembourg)fr_LU_EURO French (Luxembourg,Euro)hr Croatianhr_HR Croatian (Croatia)hu Hungarianhu_HU Hungarian (Hungary)is Icelandicis_IS Icelandic (Iceland)it Italianit_CH Italian (Switzerland)it_IT Italian (Italy)it_IT_EURO Italian (Italy,Euro)iw Hebrewiw_IL Hebrew (Israel)ja Japaneseja_JP Japanese (Japan)ko Koreanko_KR Korean (South Korea)lt Lithuanianlt_LT Lithuanian (Lithuania)lv Latvian (Lettish)lv_LV Latvian (Lettish) (Latvia)mk Macedonianmk_MK Macedonian (Macedonia)nl Dutchnl_BE Dutch (Belgium)nl_BE_EURO Dutch (Belgium,Euro)nl_NL Dutch (Netherlands)nl_NL_EURO Dutch (Netherlands,Euro)no Norwegianno_NO Norwegian (Norway)no_NO_NY Norwegian (Norway,Nynorsk)pl Polishpl_PL Polish (Poland)pt Portuguesept_BR Portuguese (Brazil)pt_PT Portuguese (Portugal)pt_PT_EURO Portuguese (Portugal,Euro)ro Romanianro_RO Romanian (Romania)ru Russianru_RU Russian (Russia)sh Serbo-Croatiansh_YU Serbo-Croatian (Yugoslavia)sk Slovaksk_SK Slovak (Slovakia)sl Sloveniansl_SI Slovenian (Slovenia)sq Albaniansq_AL Albanian (Albania)sr Serbiansr_YU Serbian (Yugoslavia)sv Swedishsv_SE Swedish (Sweden)th Thaith_TH Thai (Thailand)tr Turkishtr_TR Turkish (Turkey)uk Ukrainianuk_UA Ukrainian (Ukraine)zh Chinesezh_CN Chinese (China)zh_HK Chinese (Hong Kong)zh_TW Chinese (Taiwan)======System property======== -- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386java.vm.version=1.3.1_04-b02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=:java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=/home/chedong/src/char_testjava.runtime.version=1.3.1_04-b02java.awt.graphicsenv=sun.awt.X11GraphicsEnvironmentos.arch=i386java.io.tmpdir=/tmpline.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Linuxjava.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386:/u...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=2.4.7-10user.home=/home/chedonguser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.motif.PSPrinterJobfile.encoding=ISO-8859-1
java.specification.version=1.3
user.name=chedong
java.class.path=/home/chedong/classes
java.vm.specification.version=1.0
java.home=/usr/java/jdk1.3.1_04/jre
user.language=en
java.specification.vendor=Sun Microsystems Inc.
java.vm.info=mixed mode
java.version=1.3.1_04
java.ext.dirs=/usr/java/jdk1.3.1_04/jre/lib/ext
sun.boot.class.path=/usr/java/jdk1.3.1_04/jre/lib/rt.jar:...
java.vendor=Sun Microsystems Inc.
file.separator=/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=US
sun.cpu.isalist=
Hello, it's: Tue Jul 30 11:07:34 CST 2002======System available locales:========en 英文en_US 英文 (美国)ar 阿拉伯文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_SD 阿拉伯文 (苏丹)ar_SY 阿拉伯文 (叙利亚)ar_TN 阿拉伯文 (突尼斯)ar_YE 阿拉伯文 (也门)be 白俄罗斯文be_BY 白俄罗斯文 (白俄罗斯)bg 保加利亚文bg_BG 保加利亚文 (保加利亚)ca 加泰罗尼亚文ca_ES 加泰罗尼亚文 (西班牙)ca_ES_EURO 加泰罗尼亚文 (西班牙,Euro)cs 捷克文cs_CZ 捷克文 (捷克共和国)da 丹麦文da_DK 丹麦文 (丹麦)de 德文de_AT 德文 (奥地利)de_AT_EURO 德文 (奥地利,Euro)de_CH 德文 (瑞士)de_DE 德文 (德国)de_DE_EURO 德文 (德国,Euro)de_LU 德文 (卢森堡)de_LU_EURO 德文 (卢森堡,Euro)el 希腊文el_GR 希腊文 (希腊)en_AU 英文 (澳大利亚)en_CA 英文 (加拿大)en_GB 英文 (英国)en_IE 英文 (爱尔兰)en_IE_EURO 英文 (爱尔兰,Euro)en_NZ 英文 (新西兰)en_ZA 英文 (南非)es 西班牙文es_BO 西班牙文 (玻利维亚)es_AR 西班牙文 (阿根廷)es_CL 西班牙文 (智利)es_CO 西班牙文 (哥伦比亚)es_CR 西班牙文 (哥斯达黎加)es_DO 西班牙文 (多米尼加共和国)es_EC 西班牙文 (厄瓜多尔)es_ES 西班牙文 (西班牙)es_ES_EURO 西班牙文 (西班牙,Euro)es_GT 西班牙文 (危地马拉)es_HN 西班牙文 (洪都拉斯)es_MX 西班牙文 (墨西哥)es_NI 西班牙文 (尼加拉瓜)et 爱沙尼亚文es_PA 西班牙文 (巴拿马)es_PE 西班牙文 (秘鲁)es_PR 西班牙文 (波多黎哥)es_PY 西班牙文 (巴拉圭)es_SV 西班牙文 (萨尔瓦多)es_UY 西班牙文 (乌拉圭)es_VE 西班牙文 (委内瑞拉)et_EE 爱沙尼亚文 (爱沙尼亚)fi 芬兰文fi_FI 芬兰文 (芬兰)fi_FI_EURO 芬兰文 (芬兰,Euro)fr 法文fr_BE 法文 (比利时)fr_BE_EURO 法文 (比利时,Euro)fr_CA 法文 (加拿大)fr_CH 法文 (瑞士)fr_FR 法文 (法国)fr_FR_EURO 法文 (法国,Euro)fr_LU 法文 (卢森堡)fr_LU_EURO 法文 (卢森堡,Euro)hr 克罗地亚文hr_HR 克罗地亚文 (克罗地亚)hu 匈牙利文hu_HU 匈牙利文 (匈牙利)is 冰岛文is_IS 冰岛文 (冰岛)it 意大利文it_CH 意大利文 (瑞士)it_IT 意大利文 (意大利)it_IT_EURO 意大利文 (意大利,Euro)iw 希伯来文iw_IL 希伯来文 (以色列)ja 日文ja_JP 日文 (日本)ko 朝鲜文ko_KR 朝鲜文 (南朝鲜)lt 立陶宛文lt_LT 立陶宛文 (立陶宛)lv 拉托维亚文(列托)lv_LV 拉托维亚文(列托) (拉脱维亚)mk 马其顿文mk_MK 马其顿文 (马其顿王国)nl 荷兰文nl_BE 荷兰文 (比利时)nl_BE_EURO 荷兰文 (比利时,Euro)nl_NL 荷兰文 (荷兰)nl_NL_EURO 荷兰文 (荷兰,Euro)no 挪威文no_NO 挪威文 (挪威)no_NO_NY 挪威文 (挪威,Nynorsk)pl 波兰文pl_PL 波兰文 (波兰)pt 葡萄牙文pt_BR 葡萄牙文 (巴西)pt_PT 葡萄牙文 (葡萄牙)pt_PT_EURO 葡萄牙文 (葡萄牙,Euro)ro 罗马尼亚文ro_RO 罗马尼亚文 (罗马尼亚)ru 俄文ru_RU 俄文 (俄罗斯)sh 塞波尼斯-克罗地亚文sh_YU 塞波尼斯-克罗地亚文 (南斯拉夫)sk 斯洛伐克文sk_SK 斯洛伐克文 (斯洛伐克)sl 斯洛文尼亚文sl_SI 斯洛文尼亚文 (斯洛文尼亚)sq 阿尔巴尼亚文sq_AL 阿尔巴尼亚文 (阿尔巴尼亚)sr 塞尔维亚文sr_YU 塞尔维亚文 (南斯拉夫)sv 瑞典文sv_SE 瑞典文 (瑞典)th 泰文th_TH 泰文 (泰国)tr 土耳其文tr_TR 土耳其文 (土耳其)uk 乌克兰文uk_UA 乌克兰文 (乌克兰)zh 中文zh_CN 中文 (中国)zh_HK 中文 (香港)zh_TW 中文 (台湾)======System property========-- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386java.vm.version=1.3.1_04-b02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=:java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=/home/chedong/src/char_testjava.runtime.version=1.3.1_04-b02java.awt.graphicsenv=sun.awt.X11GraphicsEnvironmentos.arch=i386java.io.tmpdir=/tmpline.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Linuxjava.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386:/u...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=2.4.7-10user.home=/home/chedonguser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.motif.PSPrinterJobfile.encoding=GBK
java.specification.version=1.3
user.name=chedong
java.class.path=/home/chedong/classes
java.vm.specification.version=1.0
java.home=/usr/java/jdk1.3.1_04/jre
user.language=zh
java.specification.vendor=Sun Microsystems Inc.
java.vm.info=mixed mode
java.version=1.3.1_04
java.ext.dirs=/usr/java/jdk1.3.1_04/jre/lib/ext
sun.boot.class.path=/usr/java/jdk1.3.1_04/jre/lib/rt.jar:...
java.vendor=Sun Microsystems Inc.
file.separator=/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=CN
sun.cpu.isalist=
Hello, it's: Tue Jul 30 11:49:36 CST 2002======System available locales:========en Englishen_US English (United States)ar Arabicar_AE Arabic (United Arab Emirates)ar_BH Arabic (Bahrain)ar_DZ Arabic (Algeria)ar_EG Arabic (Egypt)ar_IQ Arabic (Iraq)ar_JO Arabic (Jordan)ar_KW Arabic (Kuwait)ar_LB Arabic (Lebanon)ar_LY Arabic (Libya)ar_MA Arabic (Morocco)ar_OM Arabic (Oman)ar_QA Arabic (Qatar)ar_SA Arabic (Saudi Arabia)ar_SD Arabic (Sudan)ar_SY Arabic (Syria)ar_TN Arabic (Tunisia)ar_YE Arabic (Yemen)be Byelorussianbe_BY Byelorussian (Belarus)bg Bulgarianbg_BG Bulgarian (Bulgaria)ca Catalanca_ES Catalan (Spain)ca_ES_EURO Catalan (Spain,Euro)cs Czechcs_CZ Czech (Czech Republic)da Danishda_DK Danish (Denmark)de Germande_AT German (Austria)de_AT_EURO German (Austria,Euro)de_CH German (Switzerland)de_DE German (Germany)de_DE_EURO German (Germany,Euro)de_LU German (Luxembourg)de_LU_EURO German (Luxembourg,Euro)el Greekel_GR Greek (Greece)en_AU English (Australia)en_CA English (Canada)en_GB English (United Kingdom)en_IE English (Ireland)en_IE_EURO English (Ireland,Euro)en_NZ English (New Zealand)en_ZA English (South Africa)es Spanishes_AR Spanish (Argentina)es_BO Spanish (Bolivia)es_CL Spanish (Chile)es_CO Spanish (Colombia)es_CR Spanish (Costa Rica)es_DO Spanish (Dominican Republic)es_EC Spanish (Ecuador)es_ES Spanish (Spain)es_ES_EURO Spanish (Spain,Euro)es_GT Spanish (Guatemala)es_HN Spanish (Honduras)es_MX Spanish (Mexico)es_NI Spanish (Nicaragua)es_PA Spanish (Panama)es_PE Spanish (Peru)es_PR Spanish (Puerto Rico)es_PY Spanish (Paraguay)es_SV Spanish (El Salvador)es_UY Spanish (Uruguay)es_VE Spanish (Venezuela)et Estonianet_EE Estonian (Estonia)fi Finnishfi_FI Finnish (Finland)fi_FI_EURO Finnish (Finland,Euro)fr Frenchfr_BE French (Belgium)fr_BE_EURO French (Belgium,Euro)fr_CA French (Canada)fr_CH French (Switzerland)fr_FR French (France)fr_FR_EURO French (France,Euro)fr_LU French (Luxembourg)fr_LU_EURO French (Luxembourg,Euro)hr Croatianhr_HR Croatian (Croatia)hu Hungarianhu_HU Hungarian (Hungary)is Icelandicis_IS Icelandic (Iceland)it Italianit_CH Italian (Switzerland)it_IT Italian (Italy)it_IT_EURO Italian (Italy,Euro)iw Hebrewiw_IL Hebrew (Israel)ja Japaneseja_JP Japanese (Japan)ko 韩文ko_KR 韩文 (大韩民国)lt Lithuanianlt_LT Lithuanian (Lithuania)lv Latvian (Lettish)lv_LV Latvian (Lettish) (Latvia)mk Macedonianmk_MK Macedonian (Macedonia)nl Dutchnl_BE Dutch (Belgium)nl_BE_EURO Dutch (Belgium,Euro)nl_NL Dutch (Netherlands)nl_NL_EURO Dutch (Netherlands,Euro)no Norwegianno_NO Norwegian (Norway)no_NO_NY Norwegian (Norway,Nynorsk)pl Polishpl_PL Polish (Poland)pt Portuguesept_BR Portuguese (Brazil)pt_PT Portuguese (Portugal)pt_PT_EURO Portuguese (Portugal,Euro)ro Romanianro_RO Romanian (Romania)ru Russianru_RU Russian (Russia)sh Serbo-Croatiansh_YU Serbo-Croatian (Yugoslavia)sk Slovaksk_SK Slovak (Slovakia)sl Sloveniansl_SI Slovenian (Slovenia)sq Albaniansq_AL Albanian (Albania)sr Serbiansr_YU Serbian (Yugoslavia)sv Swedishsv_SE Swedish (Sweden)th Thaith_TH Thai (Thailand)tr Turkishtr_TR Turkish (Turkey)uk Ukrainianuk_UA Ukrainian (Ukraine)zh 中文zh_CN 中文 (中华人民共和国)zh_HK 中文 (香港)zh_TW 中文 (台湾)======System property========-- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...java.vm.version=1.3.0_02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=;java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=D:\java\src\char_testjava.runtime.version=1.3.0_02java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironmentos.arch=x86java.io.tmpdir=D:\TEMP\line.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Windows 98java.library.path=C:\WINDOWS;.;C:\WINDOWS\SYSTEM;C:\WIN...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=4.90user.home=C:\WINDOWSuser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.windows.WPrinterJobfile.encoding=GBK
java.specification.version=1.3
user.name=Sicci
java.class.path=d:\java\classes
java.vm.specification.version=1.0
java.home=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_02
user.language=zh
java.specification.vendor=Sun Microsystems Inc.
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.3.0_02
java.ext.dirs=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
sun.boot.class.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=CN
sun.cpu.isalist=pentium i486 i386
Hello, it's: Tue Jul 30 11:53:27 CST 2002======System available locales:========en Englishen_US English (United States)ar Arabicar_AE Arabic (United Arab Emirates)ar_BH Arabic (Bahrain)ar_DZ Arabic (Algeria)ar_EG Arabic (Egypt)ar_IQ Arabic (Iraq)ar_JO Arabic (Jordan)ar_KW Arabic (Kuwait)ar_LB Arabic (Lebanon)ar_LY Arabic (Libya)ar_MA Arabic (Morocco)ar_OM Arabic (Oman)ar_QA Arabic (Qatar)ar_SA Arabic (Saudi Arabia)ar_SD Arabic (Sudan)ar_SY Arabic (Syria)ar_TN Arabic (Tunisia)ar_YE Arabic (Yemen)be Byelorussianbe_BY Byelorussian (Belarus)bg Bulgarianbg_BG Bulgarian (Bulgaria)ca Catalanca_ES Catalan (Spain)ca_ES_EURO Catalan (Spain,Euro)cs Czechcs_CZ Czech (Czech Republic)da Danishda_DK Danish (Denmark)de Germande_AT German (Austria)de_AT_EURO German (Austria,Euro)de_CH German (Switzerland)de_DE German (Germany)de_DE_EURO German (Germany,Euro)de_LU German (Luxembourg)de_LU_EURO German (Luxembourg,Euro)el Greekel_GR Greek (Greece)en_AU English (Australia)en_CA English (Canada)en_GB English (United Kingdom)en_IE English (Ireland)en_IE_EURO English (Ireland,Euro)en_NZ English (New Zealand)en_ZA English (South Africa)es Spanishes_AR Spanish (Argentina)es_BO Spanish (Bolivia)es_CL Spanish (Chile)es_CO Spanish (Colombia)es_CR Spanish (Costa Rica)es_DO Spanish (Dominican Republic)es_EC Spanish (Ecuador)es_ES Spanish (Spain)es_ES_EURO Spanish (Spain,Euro)es_GT Spanish (Guatemala)es_HN Spanish (Honduras)es_MX Spanish (Mexico)es_NI Spanish (Nicaragua)es_PA Spanish (Panama)es_PE Spanish (Peru)es_PR Spanish (Puerto Rico)es_PY Spanish (Paraguay)es_SV Spanish (El Salvador)es_UY Spanish (Uruguay)es_VE Spanish (Venezuela)et Estonianet_EE Estonian (Estonia)fi Finnishfi_FI Finnish (Finland)fi_FI_EURO Finnish (Finland,Euro)fr Frenchfr_BE French (Belgium)fr_BE_EURO French (Belgium,Euro)fr_CA French (Canada)fr_CH French (Switzerland)fr_FR French (France)fr_FR_EURO French (France,Euro)fr_LU French (Luxembourg)fr_LU_EURO French (Luxembourg,Euro)hr Croatianhr_HR Croatian (Croatia)hu Hungarianhu_HU Hungarian (Hungary)is Icelandicis_IS Icelandic (Iceland)it Italianit_CH Italian (Switzerland)it_IT Italian (Italy)it_IT_EURO Italian (Italy,Euro)iw Hebrewiw_IL Hebrew (Israel)ja Japaneseja_JP Japanese (Japan)ko Koreanko_KR Korean (South Korea)lt Lithuanianlt_LT Lithuanian (Lithuania)lv Latvian (Lettish)lv_LV Latvian (Lettish) (Latvia)mk Macedonianmk_MK Macedonian (Macedonia)nl Dutchnl_BE Dutch (Belgium)nl_BE_EURO Dutch (Belgium,Euro)nl_NL Dutch (Netherlands)nl_NL_EURO Dutch (Netherlands,Euro)no Norwegianno_NO Norwegian (Norway)no_NO_NY Norwegian (Norway,Nynorsk)pl Polishpl_PL Polish (Poland)pt Portuguesept_BR Portuguese (Brazil)pt_PT Portuguese (Portugal)pt_PT_EURO Portuguese (Portugal,Euro)ro Romanianro_RO Romanian (Romania)ru Russianru_RU Russian (Russia)sh Serbo-Croatiansh_YU Serbo-Croatian (Yugoslavia)sk Slovaksk_SK Slovak (Slovakia)sl Sloveniansl_SI Slovenian (Slovenia)sq Albaniansq_AL Albanian (Albania)sr Serbiansr_YU Serbian (Yugoslavia)sv Swedishsv_SE Swedish (Sweden)th Thaith_TH Thai (Thailand)tr Turkishtr_TR Turkish (Turkey)uk Ukrainianuk_UA Ukrainian (Ukraine)zh Chinesezh_CN Chinese (China)zh_HK Chinese (Hong Kong)zh_TW Chinese (Taiwan)======System property========-- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...java.vm.version=1.3.0_02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=;java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=D:\java\src\char_testjava.runtime.version=1.3.0_02java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironmentos.arch=x86java.io.tmpdir=D:\TEMP\line.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Windows 98java.library.path=C:\WINDOWS;.;C:\WINDOWS\SYSTEM;C:\WIN...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=4.90user.home=C:\WINDOWSuser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.windows.WPrinterJobfile.encoding=Cp1252
java.specification.version=1.3
user.name=Sicci
java.class.path=d:\java\classes
java.vm.specification.version=1.0
java.home=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_02
user.language=en
java.specification.vendor=Sun Microsystems Inc.
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.3.0_02
java.ext.dirs=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
sun.boot.class.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=GB
sun.cpu.isalist=pentium i486 i386
结论1:
JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关。所以当设置成相同的LOCALE时,Linux和Windows下的缺省编码方式是没有区别的(可以认为cp1252=ISO-8859-1都是一样的西文编码方式,只包含255以下的拉丁字符),因此后面的测试2我只列出了GNU/Linux下LOCALE分别设置成zh_CN和en_US的测试结果输出。以下测试如果在Windows下分别按照不同的区域和字符集设置后试验的输出是一样的。
试验2:Java的输入输出过程中的字节流到字符流的转换过程
通过这个HelloUnicode.java程序,演示说明"Hello world 世界你好"这个字符串(16个字符)在不同缺省系统编码方式下的处理效果。在编码/解码的每个步骤之后,都打印出了相应字符串每个字符(Charactor)的byte值,short值和所在的UNICODE区间。
LANG=en_US LC_ALL=en_US LANG=zh_CN LC_ALL=zh_CN.GBK
========testing1: write hello world to files========[test 1-1]: with system default encoding=ISO-8859-1string=Hello world 世界你好 length=20char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATINchar[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATINchar[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATINchar[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATINchar[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATINchar[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[12]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[13]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[14]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[15]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[16]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[17]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[18]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[19]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT第1步:在英文编码环境下,虽然屏幕上正确的显示了中文,但实际上它打印的是“半个”汉字,将结果写入第1个文件 hello.orig.html
[test 1-2]: getBytes with platform default encoding and decoding as gb2312:
string=Hello world ???? length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='?' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='?' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='?' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='?' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
按系统缺省编码重新变成字节流,然后按照GB2312方式解码,这里虽然打印出的是问号(因为当前的英文环境下系统对于255以上的字符是不知道用什么字符表示的,因此全部用?显示)但从相应的UNICODE MAPPING和SHORT值我们可以知道字符是正确的中文但下一步的写入第2个文件html.gb2312.html,没有指定编码方式(按系统缺省的ISO-8859-1编码方式),因此从后面的测试2-2读取的结果是真的'?'了
[test 1-3]: convert string to UTF8
string=Hello world 涓栫晫浣犲ソ length=24
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='? byte=-28 \uFFFFFFE4 short=228 \uE4 LATIN_1_SUPPLEMENT
char[13]='? byte=-72 \uFFFFFFB8 short=184 \uB8 LATIN_1_SUPPLEMENT
char[14]='? byte=-106 \uFFFFFF96 short=150 \u96 LATIN_1_SUPPLEMENT
char[15]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENT
char[16]='? byte=-107 \uFFFFFF95 short=149 \u95 LATIN_1_SUPPLEMENT
char[17]='? byte=-116 \uFFFFFF8C short=140 \u8C LATIN_1_SUPPLEMENT
char[18]='? byte=-28 \uFFFFFFE4 short=228 \uE4 LATIN_1_SUPPLEMENT
char[19]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENT
char[20]='? byte=-96 \uFFFFFFA0 short=160 \uA0 LATIN_1_SUPPLEMENT
char[21]='? byte=-27 \uFFFFFFE5 short=229 \uE5 LATIN_1_SUPPLEMENT
char[22]='? byte=-91 \uFFFFFFA5 short=165 \uA5 LATIN_1_SUPPLEMENT
char[23]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENT
第3个试验,将字符流按照UTF8方式编码后,写入第3个测试文件hello.utf8.html,我们可以看到UTF8对英文没有影响,但对于其他文字使用了3字节编码方式,因此比GB2312编码方式的存储要大50%,
========Testing2: reading and decoding from files========
[test 2-1]: read hello.orig.html: decoding with system default encoding
string=Hello world 世界你好 length=20
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENT
char[13]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENT
char[14]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENT
char[15]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENT
char[16]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENT
char[17]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENT
char[18]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENT
char[19]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT
按系统从中间存储hello.orig.html文件中读取相应文件,虽然是按字节方式(半个“字”)读取的,但由于能完整的还原,因此输出显示没有错误。其实PHP等应用很少出现字符集问题其实就是这个原因,全程都是按字节流方式处理,很好的还原了输入,但这样处理的同时也失去了对字符的控制
[test 2-2]: read hello.gb2312.html: decoding as GB2312
string=Hello world ???? length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[13]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[14]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[15]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
最惨的就是输出的时候这些'?'真的是问号char(63)了,数据如果是这样就真的没救了
[test 2-3]: read hello.utf8.html: decoding as UTF8
string=Hello world ???? length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='?' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='?' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='?' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='?' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
great! 字符虽然显示为'?',但实际上字符的解码是正确的,从相应的UNICODE MAPPING就可以看的出来。
========Testing1: write hello world to files========[test 1-1]: with system default encoding=GBKstring=Hello world 世界你好 length=16char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATINchar[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATINchar[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATINchar[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATINchar[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATINchar[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS注意:在新的语言环境中做以上测试需要将源程序重新编译,最早的字节流到字符流的解码过程从JavaC编译源文件就开始了,这个测试和刚才最大的不同在于源文件中的“世界你好”这4个字是否按中文编码方式编译导程序里的,而不是按字节方式编译成8个字符(实际上对应的是8个字节)在程序里。
[test 1-2]: getBytes with platform default encoding and decoding as gb2312:
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
在中文环境下,解码和上面缺省的编码是一致的,因此输出一致
[test 1-3]: convert string to UTF8
string=Hello world 涓栫晫浣犲ソ length=18
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='涓' byte=-109 \uFFFFFF93 short=28051 \u6D93 CJK_UNIFIED_IDEOGRAPHS
char[13]='栫' byte=43 \u2B short=26667 \u682B CJK_UNIFIED_IDEOGRAPHS
char[14]='晫' byte=107 \u6B short=26219 \u666B CJK_UNIFIED_IDEOGRAPHS
char[15]='浣' byte=99 \u63 short=28003 \u6D63 CJK_UNIFIED_IDEOGRAPHS
char[16]='犲' byte=-78 \uFFFFFFB2 short=29362 \u72B2 CJK_UNIFIED_IDEOGRAPHS
char[17]='ソ' byte=-67 \uFFFFFFBD short=12477 \u30BD KATAKANA
其实我们用于测试的终端窗口就是一个GBK字符集的应用,这个输出其实都是把UNICODE按GBK字符集解码的效果。
========Testing2: reading and decoding from files========
[test 2-1]: read hello.orig.html: decoding with system default encoding
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
[test 2-2]: read hello.gb2312.html: decoding as GB2312
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
[test 2-3]: read hello.utf8.html: decoding as UTF8
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
结论:如果后台数据采用UNICODE方式的存储然后根据需要指定字符集编码、解码方式,则应用几乎可以不受前端应用所处环境字符集设置的影响
试验2的一些结论:
所有的应用都是按照字节流=>字符流=>字节流方式进行的处理的:
byte_stream ==[input decoding]==> unicode_char_stream ==[output encoding]==> byte_stream;
在Java字节流到字符流(或者反之)都是含有隐含的解码处理的(缺省是按照系统缺省编码方式);
最早的字节流解码过程从javac的代码编译就开始了;
Java中的字符character存储单位是双字节的UNICODE;
试验3:WEB应用中的输入输出中的编码问题:Java是为做国际化应用设计的,Servlet应根据浏览器语言设置自动切换字符集配置
首先一个概念:即使是基于Java的WEB应用,在服务器和客户端之间传递的仍然是字节流,比如我从一个中文客户端的浏览器表单中提交“世界你好”这4个中文字到服务器时:首先浏览器按照GBK方式编码成字节流CA C0 BD E7 C4 E3 BA C3,然后8个字节按照URLEncoding的规范转成:%CA%C0%BD%E7%C4%E3%BA%C3,服务器端的Servlet接收到请求后应该按什么解码处理,输出时又应该按什么方式编码行字节流呢?
在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:
当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK:
//auto detect broswer's languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }
输出为:
'世界你好' length=4ServletRequest's Charset Encoding = GBK ServletResponse's Charset Encoding = GBK char[0]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[2]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:
'世界你好' length=8ServletRequest's Charset Encoding = null ServletResponse's Charset Encoding = ISO-8859-1 char[0]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[1]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[2]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[3]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[4]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[5]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[6]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[7]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT
虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletResponse.html#setContentType()
以前能够配置让一个WEB应用能够在GBK方式编码的中文Windows2000服务器上和按ISO-8859-1方式编码的GNU/Linux上都能够正确的显示中文一直让我迷惑了很久。我仔细想了一下,后来终于想明白了,在一个国际化的应用中:ServletRequest和ServletResponse的编码/解码方式的确不应该根据服务器设置成固定的字符集,而应该是面向客户端语言环境进行输入/输出编码方式的自适应。一个按照国际化规范设计的WEB应用中:
在Servlet的源代码中尽量不要有中文:因为在MVC模式中,Servlet主要是控制器(C)的角色,因此,应该通过ResourceBundle机制由Servlet控制转向到相应的显示器(JSP或者XSLT)中,所以应该将与本地界面语言相关的界面显示的部分从Servlet和后台的模块中完全剥离出来,放到相应的ResourceBundle文件中或者XSLT文件中。这样源程序里完全是英文,编译时完全不需要考虑字符集的问题。
如果Servlet实在需要包含中文,则需要设置应用服务器的Javac编译选项,加上-encoding选项成系统缺省的字符集,如果把用中文编写的字符按照英文方式解码编译,然后再按照英文方式输出,虽然结果表面正确,实际上都成了面向“字节”编程。
在Servlet层,应该像GOOGLE搜索引擎那样,设计成能够根据客户端浏览器的语言环境自适应输出,为了判断浏览器的语言Servlet中应该有类似以下的代码:
public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //从HTTP请求的头信息中获取客户端的语言设置 String clientLanguage = req.getHeader("Accept-Language"); //简体中文浏览器 if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); } //繁体中文浏览器 else if ( clientLanguage.equals("zh-tw") ) { req.setCharacterEncoding("BIG5"); res.setContentType("text/html; charset=BIG5"); } //日文浏览器 else if ( clientLanguage.equals("jp") ) { req.setCharacterEncoding("SJIS"); res.setContentType("text/html; charset=SJIS"); } //缺省认为是英文浏览器 else { req.setCharacterEncoding("ISO-8859-1"); res.setContentType("text/html; charset=ISO-8859-1"); } ... //设置好request的解码方式和response的编码方式后,进行后续的操作。 //比如再转向到HelloWorld.gbk.jsp HelloWorld.big5.jsp HelloWorld.jis.jsp等 }
而SERVLET缺省将字符集设置为ISO-8859-1也许是标准制定者认为英文的浏览器占大多数吧(而且按照ISO-8859-1方式输出界面往往也是正确的)。
结论:
过以上几个Java试验程序得出的一些结论:
Java环境是基于操作系统上的一个虚拟机应用,因此,如果操作系统遵循国际化规范:JVM的缺省编码方式可以通过修改操作系统的LOCALE设置实现。对于一个Java应用来说,只要将LINUX的缺省编码方式设置成GBK,其文字编码处理应该和中文Windows平台上的表现是一致的。
redhat 6.X使用linux内核的是基于glibc2.1.X,不支持中文LOCALE,因此无法通过改变LOCALE设置改变JVM的缺省编码方式,linux内核2.4开始基于glibc.2.2.x,对中文LOCALE有了比较好的支持。
不同的JVM对字符集的支持程度不同:
比如:IBM的JVM1.3.0开始支持GB18030,SUN的JVM从1.4开始支持GB18030
正确的编码方式不一定表示能正确的显示,正确的显示还要需要相应的前端显示系统(字库)的支持
但对于Linux上的服务应用来说,往往只要能确认字符正确的按照指定的方式编码就够了
如果应用的是基于UNICODE的编码方式处理并使用UTF8字符集做集中存储,这样最便于根据客户端语言环境做本地化输出;
根据以上结论,设计一个适应多语言环境的应用,可以考虑一下2个应用处理模式:
(客户端应用或本地化应用)根据LOCALE,让Java应用根据系统LOCALE的缺省的字符集设置进行切换,按系统缺省的字符集进行编码解码,减少应用在编码处理上的复杂程度。
输入字节流 ==>按系统语言字符集设置将字节流解码==> UNICODE处理 ==> 按系统语言字符集设置将UNICODE编码成字节流 ==> 输出字节流
(服务器端或跨语言平台应用):在应用的最外端:数据输入输出判断用户语言环境,核心按照UNICODE方式处理存储。可以把各种区域性的字符集(GB2312 BIG5)看成是UNICODE的一个子集。UNICODE存储的数据可以方便的转换成任意字符集。
应用使用UTF8方式存储虽然要增加了存储空间,但也可以大大简化前端应用本地化(i10n)的复杂程度。
简体中文输入 繁体中文输入 简体中文输出 繁体中文输出 \ / \ / 判断用户语言环境:解码 判断用户语言环境:编码 \ / 中间处理过程:UNICODE | UTF8编码存储
随着UNICODE被愈来愈多的系统和平台支持:Python Perl Glibc等,但我们应该珍惜一开始就按照国际化规范设计Java,并将其和新发展起来的XML规范相配合,相信符合国际化规范的应用设计从长远来看会展现出更多的优势。
TODO:
数据库应用中的字符集问题试验:MySQL Oracle JDBC
参考文档:
Java的国际化设计
http://java.sun.com/docs/books/tutorial/i18n/index.html
Linux 国际化本地化和中文化
http://www.linuxforum.net/doc/i18n-new.html
Linux 程序员必读:中文化与GB18030标准
http://www.ccidnet.com/tech/os/2001/07/31/58_2811.html
Unicode FAQ
http://www.cl.cam.ac.uk/~mgk25/unicode.html
http://www.linuxforum.net/books/UTF-8-Unicode.html (中文版)
Java 编程技术中汉字问题的分析及解决
http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml
汉字的编码方式:
http://www.unihan.com.cn/cjk/ana17.htm
不同版本的JVM支持的编码方式
http://java.sun.com/j2se/1.3/docs/guide/intl/encoding.doc.html
http://java.sun.com/j2se/1.4/docs/guide/intl/encoding.doc.html
附录:
A. The Unicode 2.0 Character Set
Characters
Description
\u0000 - \u1FFF
Alphabets
\u0020 - \u007F
Basic Latin
\u0080 - \u00FF
Latin-1 supplement
\u0100 - \u017F
Latin extended-A
\u0180 - \u024F
Latin extended-B
\u0250 - \u02AF
IPA extensions
\u02B0 - \u02FF
Spacing modifier letters
\u0300 - \u036F
Combining diacritical marks
\u0370 - \u03FF
Greek
\u0400 - \u04FF
Cyrillic
\u0530 - \u058F
Armenian
\u0590 - \u05FF
Hebrew
\u0600 - \u06FF
Arabic
\u0900 - \u097F
Devanagari
\u0980 - \u09FF
Bengali
\u0A00 - \u0A7F
Gurmukhi
\u0A80 - \u0AFF
Gujarati
\u0B00 - \u0B7F
Oriya
\u0B80 - \u0BFF
Tamil
\u0C00 - \u0C7F
Telugu
\u0C80 - \u0CFF
Kannada
\u0D00 - \u0D7F
Malayalam
\u0E00 - \u0E7F
Thai
\u0E80 - \u0EFF
Lao
\u0F00 - \u0FBF
Tibetan
\u10A0 - \u10FF
Georgian
\u1100 - \u11FF
Hangul Jamo
\u1E00 - \u1EFF
Latin extended additional
\u1F00 - \u1FFF
Greek extended
\u2000 - \u2FFF
Symbols and punctuation
\u2000 - \u206F
General punctuation
\u2070 - \u209F
Superscripts and subscripts
\u20A0 - \u20CF
Currency symbols
\u20D0 - \u20FF
Combining diacritical marks for symbols
\u2100 - \u214F
Letterlike symbols
\u2150 - \u218F
Number forms
\u2190 - \u21FF
Arrows
\u2200 - \u22FF
Mathematical operators
\u2300 - \u23FF
Miscellaneous technical
\u2400 - \u243F
Control pictures
\u2440 - \u245F
Optical character recognition
\u2460 - \u24FF
Enclosed alphanumerics
\u2500 - \u257F
Box drawing
\u2580 - \u259F
Block elements
\u25A0 - \u25FF
Geometric shapes
\u2600 - \u26FF
Miscellaneous symbols
\u2700 - \u27BF
Dingbats
\u3000 - \u33FF
CJK auxiliary
\u3000 - \u303F
CJK symbols and punctuation
\u3040 - \u309F
Hiragana
\u30A0 - \u30FF
Katakana
\u3100 - \u312F
Bopomofo
\u3130 - \u318F
Hangul compatibility Jamo
\u3190 - \u319F
Kanbun
\u3200 - \u32FF
Enclosed CJK letters and months
\u3300 - \u33FF
CJK compatibility
\u4E00 - \u9FFF
CJK unified ideographs: Han characters used in China, Japan, Korea, Taiwan, and Vietnam
\uAC00 - \uD7A3
Hangul syllables
\uD800 - \uDFFF
Surrogates
\uD800 - \uDB7F
High surrogates
\uDB80 - \uDBFF
High private use surrogates
\uDC00 - \uDFFF
Low surrogates
\uE000 - \uF8FF
Private use
\uF900 - \uFFFF
Miscellaneous
\uF900 - \uFAFF
CJK compatibility ideographs
\uFB00 - \uFB4F
Alphabetic presentation forms
\uFB50 - \uFDFF
Arabic presentation forms-A
\uFE20 - \uFE2F
Combing half marks
\uFE30 - \uFE4F
CJK compatibility forms
\uFE50 - \uFE6F
Small form variants
\uFE70 - \uFEFE
Arabic presentation forms-B
\uFEFF
Specials
\uFF00 - \uFFEF
Halfwidth and fullwidth forms
\uFFF0 - \uFFFF
Specials
原文出处:<a href="http://www.chedong.com/tech/hello_unicode.html">http://www.chedong.com/tech/hello_unicode.html</a>
<<返回
<<返回首页
作者: 车东 Email: chedongATbigfoot.com/chedongATchedong.com
写于:2002/07 最后更新: 09/09/2006 17:09:05
Feed Back >> (Read this before you ask question)
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://www.chedong.com/tech/hello_unicode.html
关键词:linux java mutlibyte encoding locale i18n i10n chinese ISO-8859-1 GB2312 BIG5 GBK UNICODE
内容摘要:
不知道你有没有这样的感受:为什么PHP很少有乱码问题而用Java做WEB应用却这么麻烦呢?为什么在Google上能用简体中文查到繁体中文,甚至日文的结果?而且用Google的时候发现它居然能自动根据我使用浏览器的语言选择自动调出中文界面?
很多国际化应用的让我理解了这么一个道理:Unicode是为更方便的做国际化应用设计的,而Java核心的字符是基于UNICODE的,这一机制为应用提供了对中文“字”的控制(而不是字节)。但如果不仔细理解其中的规范,这种自由反而会成为累赘,从而导致更多的乱码问题:
关于字符集的一些基本概念;
试验1:显示系统的环境设置和支持的编码方式;
试验2:系统缺省编码方式对Java应用的输入输出影响;
试验3:在WEB应用中输出和输出中的字符集问题;
关于字符集的准备知识:
ISO-8859-1 GB2312 BIG5 GBK GB18030 UNICODE 为什么会有这么多字符集编码方式?
注意:以下说明不是严格定义,一些比喻仅作为方便理解使用。
假设一个字符就是棋盘上的一个棋子,有其固定的坐标,如果需要区别所有的字符,就需要有足够的棋格容纳不同的“字符”。
英文和欧洲其他语言的单字节字符集(SingleByte Charsets):
首先对于ISO-8859系列的字符集都想象成一个:2^8 = 16 * 16 = 256个格子的棋盘,这样所有的西文字符(英文)用这样一个16×16的坐标系就基本可以覆盖全了。而英文实际上只用其中小于128(\x80)的部分就够了。利用大于128部分的空间的不同定义规则形成了真对其他欧洲语言的扩展字符集:ISO-8859-2 ISO-8859-4等……
ISO-8859-1
ISO-8859-7
其他语言
英文 其他西欧字符
ōē
英文 希腊字符
μγ
英文 其他单字节
字符集
GB2312 BIG5 SJIS等多字节字符集(MultiByte Charsets):
对于亚洲语言来说:汉字这么多,用这么一个256格的小棋盘肯定放不下,所以要区别成千上万的汉字解决办法就是用2个字节(坐标)来定位一个“字”在棋盘上的位置,将以上规则做一个扩展:
如果第1个字符是小于128(\x80)的仍和英文字符集编码方式保持兼容;
如果第1个字符是大于128(\x80)的,就当成是汉字的第1个字节,这个自己和后面紧跟的1个字节组成一个汉字;
其结果相当于在位于128以上的小棋格里每个小棋格又划分出了一个16×16的小棋盘。这样一个棋盘中的格子数(可能容纳的字符数)就变成了128 + 128 * 256。按照类似的方式有了简体中文的GB2312标准,繁体中文的BIG5字符集和日文的SJIS字符集等,GB2312字符集包含大约有六仟多个常用简体汉字。
简体中文
日文SJIS
繁体中文
英文 简
体
中
文
英文 日
文
英文
繁
体
中 文
由此可以看出,所有这些从ASCII扩展式的编码方式中:英文部分都是兼容的,但扩展部分的编码方式是不兼容的,虽然很多字在3种体系中写法一致(比如“中文”这2个字)但在相应字符集中的坐标不一致,所以GB2312编写的页面用BIG5看就变得面目全非了。而且有时候经常在浏览其他非英语国家的页面时(比如包含有德语的人名时)经常出现奇怪的汉字,其实就是扩展位的编码冲突造成的。
我把GBK和GB18030理解成一个小UNICODE:GBK字符集是GB2312的扩展(K),GBK里大约有贰万玖仟多个字符,除了保持和GB2312兼容外,繁体中文字,甚至连日文的假名字符也能显示。而GB18030-2000则是一个更复杂的字符集,采用变长字节的编码方式,能够支持更多的字符。关于汉字的编码方式比较详细的定义规范可以参考:
http://www.unihan.com.cn/cjk/ana17.htm
ASCII(英文) ==> 西欧文字 ==> 东欧字符集(俄文,希腊语等) ==> 东亚字符集(GB2312 BIG5 SJIS等)==> 扩展字符集GBK GB18030这个发展过程基本上也反映了字符集标准的发展过程,但这么随着时间的推移,尤其是互联网让跨语言的信息的交互变得越来越多的时候,太多多针对本地语言的编码标准的出现导致一个应用程序的国际化变得成本非常高。尤其是你要编写一个同时包含法文和简体中文的文档,这时候一般都会想到要是用一个通用的字符集能够显示所有语言的所有文字就好了,而且这样做应用也能够比较方便的国际化,为了达到这个目标,即使应用牺牲一些空间和程序效率也是非常值得的。UNICODE就是这样一个通用的解决方案。
UNICODE双字节字符集
所以你可以把UNICODE想象成这样:让所有的字符(包括英文)都用2个字节(2个8位)表示,这样就有了一个2^(8*2) = 256 * 256 = 65536个格子的大棋盘。在这个棋盘中,这样中(简繁)日韩(还包括越南)文字作为CJK字符集都放在一定的区位内,为了减少重复,各种语言中写法一样的字共享一个“棋格”。详细的区位见附录A
Unicode:(DoubleByte Charsets)
西 C中 其
欧 J日 它
英 K韩 语
文 言
什么还要有UTF-8?毕竟互联网70%以上的信息仍然是英文。如果连英文都用2个字节存取(UCS-2),空间浪费不就太多了?所谓UTF-8就是这样一个为了提高英文存取效率的字符集转换格式:Unicode Transformation Form 8-bit form。用UTF-8,UNICODE的2字节字符用变长个(1-3个字节)表示:
对英文,仍然和ASCII一样用1个字节表示,这个字节的值小于128(\x80);
对其他语言的用一个值位于128-256之间的字节开始,再加后面紧跟的2个字节表示,一个字符一共是3个字节;
因此,在应用中程序处理过程中所有字符都是16位(双字节),但在存取转换成字节流时使用UTF-8格式转换,对于英文字符来说和原来用ASCII方式存取时相比大小仍然是一样的,而对中文来说和原来的GB2312编码方式相比,大小为:(3字节/2字节)=1.5倍
小节:
假设英文字符集是一个16×16的棋盘,么其他语言的字符集就是把高位区重新分割的(> 128)的中等棋盘,多种字符集之间互不兼容而UNICODE本身就相当于一个256×256的大棋盘,通过一定规则将英文和其他所有语言的字符都包含在内。
试验1:操作系统语言环境设置对Java应用缺省编码方式的影响
为了了解Java应用的编码处理的机制,首先要了解操作系统对JVM缺省编码方式的影响,因此我做了一个Env.java,用于打印显示不同系统下JVM的属性和系统支持的LOCALE。程序很简单:
/* * Copyright (c) 2002 Email: chedongATbigfoot.com/chedongATchedong.com * $Id: hello_unicode.html,v 1.6 2003/11/09 07:57:11 chedong Exp $ */import java.util.*;import java.text.*;/** * 目的: * 显示环境变量和JVM的缺省属性 * 输入:无 * 输出: * 1 支持的LOCALE * 2 JVM的缺省属性 */public class Env { /** * main entrance */ public static void main(String[] args) { System.out.println("Hello, it's: " + new Date()); //print available locales Locale list[] = DateFormat.getAvailableLocales(); System.out.println("======System available locales:======== "); for (int i = 0; i < list.length; i++) { System.out.println(list[i].toString() + "\t" + list[i].getDisplayName()); } //print JVM default properties System.out.println("======System property======== "); System.getProperties().list(System.out); }}
最需要注意的是JVM的file.encoding属性,这个属性确定了JVM的缺省的编码/解码方式:从而影响应用中所有字节流==>字符流的解码方式 ,字符流==>字节流的编码方式。
LINUX下的LOCALE可以通过 LANG=zh_CN; LC_ALL=zh_CN.GBK; export LANG LC_ALL 设置。locale 命令可以显示系统当前的环境设置
Windows的LOCALE可以通过 控制面板==>区域设置 设置实现
GNU/Linux 2.4.x (J2SE1.3.1)
LANG=en_US LC_ALL=en_US GNU/Linux 2.4.x (J2SE1.3.1)
LANG=zh_CN LC_ALL=zh_CN.GBK Windows 2000(J2SE1.3.0)
区域设置:中国 中文 Windows 2000(J2SE1.3.0)
区域设置:英国 英文
Hello, it's: Tue Jul 30 11:05:44 CST 2002======System available locales:======== en Englishen_US English (United States)ar Arabicar_AE Arabic (United Arab Emirates)ar_BH Arabic (Bahrain)ar_DZ Arabic (Algeria)ar_EG Arabic (Egypt)ar_IQ Arabic (Iraq)ar_JO Arabic (Jordan)ar_KW Arabic (Kuwait)ar_LB Arabic (Lebanon)ar_LY Arabic (Libya)ar_MA Arabic (Morocco)ar_OM Arabic (Oman)ar_QA Arabic (Qatar)ar_SA Arabic (Saudi Arabia)ar_SD Arabic (Sudan)ar_SY Arabic (Syria)ar_TN Arabic (Tunisia)ar_YE Arabic (Yemen)be Byelorussianbe_BY Byelorussian (Belarus)bg Bulgarianbg_BG Bulgarian (Bulgaria)ca Catalanca_ES Catalan (Spain)ca_ES_EURO Catalan (Spain,Euro)cs Czechcs_CZ Czech (Czech Republic)da Danishda_DK Danish (Denmark)de Germande_AT German (Austria)de_AT_EURO German (Austria,Euro)de_CH German (Switzerland)de_DE German (Germany)de_DE_EURO German (Germany,Euro)de_LU German (Luxembourg)de_LU_EURO German (Luxembourg,Euro)el Greekel_GR Greek (Greece)en_AU English (Australia)en_CA English (Canada)en_GB English (United Kingdom)en_IE English (Ireland)en_IE_EURO English (Ireland,Euro)en_NZ English (New Zealand)en_ZA English (South Africa)es Spanishes_BO Spanish (Bolivia)es_AR Spanish (Argentina)es_CL Spanish (Chile)es_CO Spanish (Colombia)es_CR Spanish (Costa Rica)es_DO Spanish (Dominican Republic)es_EC Spanish (Ecuador)es_ES Spanish (Spain)es_ES_EURO Spanish (Spain,Euro)es_GT Spanish (Guatemala)es_HN Spanish (Honduras)es_MX Spanish (Mexico)es_NI Spanish (Nicaragua)et Estonianes_PA Spanish (Panama)es_PE Spanish (Peru)es_PR Spanish (Puerto Rico)es_PY Spanish (Paraguay)es_SV Spanish (El Salvador)es_UY Spanish (Uruguay)es_VE Spanish (Venezuela)et_EE Estonian (Estonia)fi Finnishfi_FI Finnish (Finland)fi_FI_EURO Finnish (Finland,Euro)fr Frenchfr_BE French (Belgium)fr_BE_EURO French (Belgium,Euro)fr_CA French (Canada)fr_CH French (Switzerland)fr_FR French (France)fr_FR_EURO French (France,Euro)fr_LU French (Luxembourg)fr_LU_EURO French (Luxembourg,Euro)hr Croatianhr_HR Croatian (Croatia)hu Hungarianhu_HU Hungarian (Hungary)is Icelandicis_IS Icelandic (Iceland)it Italianit_CH Italian (Switzerland)it_IT Italian (Italy)it_IT_EURO Italian (Italy,Euro)iw Hebrewiw_IL Hebrew (Israel)ja Japaneseja_JP Japanese (Japan)ko Koreanko_KR Korean (South Korea)lt Lithuanianlt_LT Lithuanian (Lithuania)lv Latvian (Lettish)lv_LV Latvian (Lettish) (Latvia)mk Macedonianmk_MK Macedonian (Macedonia)nl Dutchnl_BE Dutch (Belgium)nl_BE_EURO Dutch (Belgium,Euro)nl_NL Dutch (Netherlands)nl_NL_EURO Dutch (Netherlands,Euro)no Norwegianno_NO Norwegian (Norway)no_NO_NY Norwegian (Norway,Nynorsk)pl Polishpl_PL Polish (Poland)pt Portuguesept_BR Portuguese (Brazil)pt_PT Portuguese (Portugal)pt_PT_EURO Portuguese (Portugal,Euro)ro Romanianro_RO Romanian (Romania)ru Russianru_RU Russian (Russia)sh Serbo-Croatiansh_YU Serbo-Croatian (Yugoslavia)sk Slovaksk_SK Slovak (Slovakia)sl Sloveniansl_SI Slovenian (Slovenia)sq Albaniansq_AL Albanian (Albania)sr Serbiansr_YU Serbian (Yugoslavia)sv Swedishsv_SE Swedish (Sweden)th Thaith_TH Thai (Thailand)tr Turkishtr_TR Turkish (Turkey)uk Ukrainianuk_UA Ukrainian (Ukraine)zh Chinesezh_CN Chinese (China)zh_HK Chinese (Hong Kong)zh_TW Chinese (Taiwan)======System property======== -- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386java.vm.version=1.3.1_04-b02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=:java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=/home/chedong/src/char_testjava.runtime.version=1.3.1_04-b02java.awt.graphicsenv=sun.awt.X11GraphicsEnvironmentos.arch=i386java.io.tmpdir=/tmpline.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Linuxjava.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386:/u...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=2.4.7-10user.home=/home/chedonguser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.motif.PSPrinterJobfile.encoding=ISO-8859-1
java.specification.version=1.3
user.name=chedong
java.class.path=/home/chedong/classes
java.vm.specification.version=1.0
java.home=/usr/java/jdk1.3.1_04/jre
user.language=en
java.specification.vendor=Sun Microsystems Inc.
java.vm.info=mixed mode
java.version=1.3.1_04
java.ext.dirs=/usr/java/jdk1.3.1_04/jre/lib/ext
sun.boot.class.path=/usr/java/jdk1.3.1_04/jre/lib/rt.jar:...
java.vendor=Sun Microsystems Inc.
file.separator=/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=US
sun.cpu.isalist=
Hello, it's: Tue Jul 30 11:07:34 CST 2002======System available locales:========en 英文en_US 英文 (美国)ar 阿拉伯文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_SD 阿拉伯文 (苏丹)ar_SY 阿拉伯文 (叙利亚)ar_TN 阿拉伯文 (突尼斯)ar_YE 阿拉伯文 (也门)be 白俄罗斯文be_BY 白俄罗斯文 (白俄罗斯)bg 保加利亚文bg_BG 保加利亚文 (保加利亚)ca 加泰罗尼亚文ca_ES 加泰罗尼亚文 (西班牙)ca_ES_EURO 加泰罗尼亚文 (西班牙,Euro)cs 捷克文cs_CZ 捷克文 (捷克共和国)da 丹麦文da_DK 丹麦文 (丹麦)de 德文de_AT 德文 (奥地利)de_AT_EURO 德文 (奥地利,Euro)de_CH 德文 (瑞士)de_DE 德文 (德国)de_DE_EURO 德文 (德国,Euro)de_LU 德文 (卢森堡)de_LU_EURO 德文 (卢森堡,Euro)el 希腊文el_GR 希腊文 (希腊)en_AU 英文 (澳大利亚)en_CA 英文 (加拿大)en_GB 英文 (英国)en_IE 英文 (爱尔兰)en_IE_EURO 英文 (爱尔兰,Euro)en_NZ 英文 (新西兰)en_ZA 英文 (南非)es 西班牙文es_BO 西班牙文 (玻利维亚)es_AR 西班牙文 (阿根廷)es_CL 西班牙文 (智利)es_CO 西班牙文 (哥伦比亚)es_CR 西班牙文 (哥斯达黎加)es_DO 西班牙文 (多米尼加共和国)es_EC 西班牙文 (厄瓜多尔)es_ES 西班牙文 (西班牙)es_ES_EURO 西班牙文 (西班牙,Euro)es_GT 西班牙文 (危地马拉)es_HN 西班牙文 (洪都拉斯)es_MX 西班牙文 (墨西哥)es_NI 西班牙文 (尼加拉瓜)et 爱沙尼亚文es_PA 西班牙文 (巴拿马)es_PE 西班牙文 (秘鲁)es_PR 西班牙文 (波多黎哥)es_PY 西班牙文 (巴拉圭)es_SV 西班牙文 (萨尔瓦多)es_UY 西班牙文 (乌拉圭)es_VE 西班牙文 (委内瑞拉)et_EE 爱沙尼亚文 (爱沙尼亚)fi 芬兰文fi_FI 芬兰文 (芬兰)fi_FI_EURO 芬兰文 (芬兰,Euro)fr 法文fr_BE 法文 (比利时)fr_BE_EURO 法文 (比利时,Euro)fr_CA 法文 (加拿大)fr_CH 法文 (瑞士)fr_FR 法文 (法国)fr_FR_EURO 法文 (法国,Euro)fr_LU 法文 (卢森堡)fr_LU_EURO 法文 (卢森堡,Euro)hr 克罗地亚文hr_HR 克罗地亚文 (克罗地亚)hu 匈牙利文hu_HU 匈牙利文 (匈牙利)is 冰岛文is_IS 冰岛文 (冰岛)it 意大利文it_CH 意大利文 (瑞士)it_IT 意大利文 (意大利)it_IT_EURO 意大利文 (意大利,Euro)iw 希伯来文iw_IL 希伯来文 (以色列)ja 日文ja_JP 日文 (日本)ko 朝鲜文ko_KR 朝鲜文 (南朝鲜)lt 立陶宛文lt_LT 立陶宛文 (立陶宛)lv 拉托维亚文(列托)lv_LV 拉托维亚文(列托) (拉脱维亚)mk 马其顿文mk_MK 马其顿文 (马其顿王国)nl 荷兰文nl_BE 荷兰文 (比利时)nl_BE_EURO 荷兰文 (比利时,Euro)nl_NL 荷兰文 (荷兰)nl_NL_EURO 荷兰文 (荷兰,Euro)no 挪威文no_NO 挪威文 (挪威)no_NO_NY 挪威文 (挪威,Nynorsk)pl 波兰文pl_PL 波兰文 (波兰)pt 葡萄牙文pt_BR 葡萄牙文 (巴西)pt_PT 葡萄牙文 (葡萄牙)pt_PT_EURO 葡萄牙文 (葡萄牙,Euro)ro 罗马尼亚文ro_RO 罗马尼亚文 (罗马尼亚)ru 俄文ru_RU 俄文 (俄罗斯)sh 塞波尼斯-克罗地亚文sh_YU 塞波尼斯-克罗地亚文 (南斯拉夫)sk 斯洛伐克文sk_SK 斯洛伐克文 (斯洛伐克)sl 斯洛文尼亚文sl_SI 斯洛文尼亚文 (斯洛文尼亚)sq 阿尔巴尼亚文sq_AL 阿尔巴尼亚文 (阿尔巴尼亚)sr 塞尔维亚文sr_YU 塞尔维亚文 (南斯拉夫)sv 瑞典文sv_SE 瑞典文 (瑞典)th 泰文th_TH 泰文 (泰国)tr 土耳其文tr_TR 土耳其文 (土耳其)uk 乌克兰文uk_UA 乌克兰文 (乌克兰)zh 中文zh_CN 中文 (中国)zh_HK 中文 (香港)zh_TW 中文 (台湾)======System property========-- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386java.vm.version=1.3.1_04-b02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=:java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=/home/chedong/src/char_testjava.runtime.version=1.3.1_04-b02java.awt.graphicsenv=sun.awt.X11GraphicsEnvironmentos.arch=i386java.io.tmpdir=/tmpline.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Linuxjava.library.path=/usr/java/jdk1.3.1_04/jre/lib/i386:/u...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=2.4.7-10user.home=/home/chedonguser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.motif.PSPrinterJobfile.encoding=GBK
java.specification.version=1.3
user.name=chedong
java.class.path=/home/chedong/classes
java.vm.specification.version=1.0
java.home=/usr/java/jdk1.3.1_04/jre
user.language=zh
java.specification.vendor=Sun Microsystems Inc.
java.vm.info=mixed mode
java.version=1.3.1_04
java.ext.dirs=/usr/java/jdk1.3.1_04/jre/lib/ext
sun.boot.class.path=/usr/java/jdk1.3.1_04/jre/lib/rt.jar:...
java.vendor=Sun Microsystems Inc.
file.separator=/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=CN
sun.cpu.isalist=
Hello, it's: Tue Jul 30 11:49:36 CST 2002======System available locales:========en Englishen_US English (United States)ar Arabicar_AE Arabic (United Arab Emirates)ar_BH Arabic (Bahrain)ar_DZ Arabic (Algeria)ar_EG Arabic (Egypt)ar_IQ Arabic (Iraq)ar_JO Arabic (Jordan)ar_KW Arabic (Kuwait)ar_LB Arabic (Lebanon)ar_LY Arabic (Libya)ar_MA Arabic (Morocco)ar_OM Arabic (Oman)ar_QA Arabic (Qatar)ar_SA Arabic (Saudi Arabia)ar_SD Arabic (Sudan)ar_SY Arabic (Syria)ar_TN Arabic (Tunisia)ar_YE Arabic (Yemen)be Byelorussianbe_BY Byelorussian (Belarus)bg Bulgarianbg_BG Bulgarian (Bulgaria)ca Catalanca_ES Catalan (Spain)ca_ES_EURO Catalan (Spain,Euro)cs Czechcs_CZ Czech (Czech Republic)da Danishda_DK Danish (Denmark)de Germande_AT German (Austria)de_AT_EURO German (Austria,Euro)de_CH German (Switzerland)de_DE German (Germany)de_DE_EURO German (Germany,Euro)de_LU German (Luxembourg)de_LU_EURO German (Luxembourg,Euro)el Greekel_GR Greek (Greece)en_AU English (Australia)en_CA English (Canada)en_GB English (United Kingdom)en_IE English (Ireland)en_IE_EURO English (Ireland,Euro)en_NZ English (New Zealand)en_ZA English (South Africa)es Spanishes_AR Spanish (Argentina)es_BO Spanish (Bolivia)es_CL Spanish (Chile)es_CO Spanish (Colombia)es_CR Spanish (Costa Rica)es_DO Spanish (Dominican Republic)es_EC Spanish (Ecuador)es_ES Spanish (Spain)es_ES_EURO Spanish (Spain,Euro)es_GT Spanish (Guatemala)es_HN Spanish (Honduras)es_MX Spanish (Mexico)es_NI Spanish (Nicaragua)es_PA Spanish (Panama)es_PE Spanish (Peru)es_PR Spanish (Puerto Rico)es_PY Spanish (Paraguay)es_SV Spanish (El Salvador)es_UY Spanish (Uruguay)es_VE Spanish (Venezuela)et Estonianet_EE Estonian (Estonia)fi Finnishfi_FI Finnish (Finland)fi_FI_EURO Finnish (Finland,Euro)fr Frenchfr_BE French (Belgium)fr_BE_EURO French (Belgium,Euro)fr_CA French (Canada)fr_CH French (Switzerland)fr_FR French (France)fr_FR_EURO French (France,Euro)fr_LU French (Luxembourg)fr_LU_EURO French (Luxembourg,Euro)hr Croatianhr_HR Croatian (Croatia)hu Hungarianhu_HU Hungarian (Hungary)is Icelandicis_IS Icelandic (Iceland)it Italianit_CH Italian (Switzerland)it_IT Italian (Italy)it_IT_EURO Italian (Italy,Euro)iw Hebrewiw_IL Hebrew (Israel)ja Japaneseja_JP Japanese (Japan)ko 韩文ko_KR 韩文 (大韩民国)lt Lithuanianlt_LT Lithuanian (Lithuania)lv Latvian (Lettish)lv_LV Latvian (Lettish) (Latvia)mk Macedonianmk_MK Macedonian (Macedonia)nl Dutchnl_BE Dutch (Belgium)nl_BE_EURO Dutch (Belgium,Euro)nl_NL Dutch (Netherlands)nl_NL_EURO Dutch (Netherlands,Euro)no Norwegianno_NO Norwegian (Norway)no_NO_NY Norwegian (Norway,Nynorsk)pl Polishpl_PL Polish (Poland)pt Portuguesept_BR Portuguese (Brazil)pt_PT Portuguese (Portugal)pt_PT_EURO Portuguese (Portugal,Euro)ro Romanianro_RO Romanian (Romania)ru Russianru_RU Russian (Russia)sh Serbo-Croatiansh_YU Serbo-Croatian (Yugoslavia)sk Slovaksk_SK Slovak (Slovakia)sl Sloveniansl_SI Slovenian (Slovenia)sq Albaniansq_AL Albanian (Albania)sr Serbiansr_YU Serbian (Yugoslavia)sv Swedishsv_SE Swedish (Sweden)th Thaith_TH Thai (Thailand)tr Turkishtr_TR Turkish (Turkey)uk Ukrainianuk_UA Ukrainian (Ukraine)zh 中文zh_CN 中文 (中华人民共和国)zh_HK 中文 (香港)zh_TW 中文 (台湾)======System property========-- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...java.vm.version=1.3.0_02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=;java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=D:\java\src\char_testjava.runtime.version=1.3.0_02java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironmentos.arch=x86java.io.tmpdir=D:\TEMP\line.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Windows 98java.library.path=C:\WINDOWS;.;C:\WINDOWS\SYSTEM;C:\WIN...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=4.90user.home=C:\WINDOWSuser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.windows.WPrinterJobfile.encoding=GBK
java.specification.version=1.3
user.name=Sicci
java.class.path=d:\java\classes
java.vm.specification.version=1.0
java.home=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_02
user.language=zh
java.specification.vendor=Sun Microsystems Inc.
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.3.0_02
java.ext.dirs=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
sun.boot.class.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=CN
sun.cpu.isalist=pentium i486 i386
Hello, it's: Tue Jul 30 11:53:27 CST 2002======System available locales:========en Englishen_US English (United States)ar Arabicar_AE Arabic (United Arab Emirates)ar_BH Arabic (Bahrain)ar_DZ Arabic (Algeria)ar_EG Arabic (Egypt)ar_IQ Arabic (Iraq)ar_JO Arabic (Jordan)ar_KW Arabic (Kuwait)ar_LB Arabic (Lebanon)ar_LY Arabic (Libya)ar_MA Arabic (Morocco)ar_OM Arabic (Oman)ar_QA Arabic (Qatar)ar_SA Arabic (Saudi Arabia)ar_SD Arabic (Sudan)ar_SY Arabic (Syria)ar_TN Arabic (Tunisia)ar_YE Arabic (Yemen)be Byelorussianbe_BY Byelorussian (Belarus)bg Bulgarianbg_BG Bulgarian (Bulgaria)ca Catalanca_ES Catalan (Spain)ca_ES_EURO Catalan (Spain,Euro)cs Czechcs_CZ Czech (Czech Republic)da Danishda_DK Danish (Denmark)de Germande_AT German (Austria)de_AT_EURO German (Austria,Euro)de_CH German (Switzerland)de_DE German (Germany)de_DE_EURO German (Germany,Euro)de_LU German (Luxembourg)de_LU_EURO German (Luxembourg,Euro)el Greekel_GR Greek (Greece)en_AU English (Australia)en_CA English (Canada)en_GB English (United Kingdom)en_IE English (Ireland)en_IE_EURO English (Ireland,Euro)en_NZ English (New Zealand)en_ZA English (South Africa)es Spanishes_AR Spanish (Argentina)es_BO Spanish (Bolivia)es_CL Spanish (Chile)es_CO Spanish (Colombia)es_CR Spanish (Costa Rica)es_DO Spanish (Dominican Republic)es_EC Spanish (Ecuador)es_ES Spanish (Spain)es_ES_EURO Spanish (Spain,Euro)es_GT Spanish (Guatemala)es_HN Spanish (Honduras)es_MX Spanish (Mexico)es_NI Spanish (Nicaragua)es_PA Spanish (Panama)es_PE Spanish (Peru)es_PR Spanish (Puerto Rico)es_PY Spanish (Paraguay)es_SV Spanish (El Salvador)es_UY Spanish (Uruguay)es_VE Spanish (Venezuela)et Estonianet_EE Estonian (Estonia)fi Finnishfi_FI Finnish (Finland)fi_FI_EURO Finnish (Finland,Euro)fr Frenchfr_BE French (Belgium)fr_BE_EURO French (Belgium,Euro)fr_CA French (Canada)fr_CH French (Switzerland)fr_FR French (France)fr_FR_EURO French (France,Euro)fr_LU French (Luxembourg)fr_LU_EURO French (Luxembourg,Euro)hr Croatianhr_HR Croatian (Croatia)hu Hungarianhu_HU Hungarian (Hungary)is Icelandicis_IS Icelandic (Iceland)it Italianit_CH Italian (Switzerland)it_IT Italian (Italy)it_IT_EURO Italian (Italy,Euro)iw Hebrewiw_IL Hebrew (Israel)ja Japaneseja_JP Japanese (Japan)ko Koreanko_KR Korean (South Korea)lt Lithuanianlt_LT Lithuanian (Lithuania)lv Latvian (Lettish)lv_LV Latvian (Lettish) (Latvia)mk Macedonianmk_MK Macedonian (Macedonia)nl Dutchnl_BE Dutch (Belgium)nl_BE_EURO Dutch (Belgium,Euro)nl_NL Dutch (Netherlands)nl_NL_EURO Dutch (Netherlands,Euro)no Norwegianno_NO Norwegian (Norway)no_NO_NY Norwegian (Norway,Nynorsk)pl Polishpl_PL Polish (Poland)pt Portuguesept_BR Portuguese (Brazil)pt_PT Portuguese (Portugal)pt_PT_EURO Portuguese (Portugal,Euro)ro Romanianro_RO Romanian (Romania)ru Russianru_RU Russian (Russia)sh Serbo-Croatiansh_YU Serbo-Croatian (Yugoslavia)sk Slovaksk_SK Slovak (Slovakia)sl Sloveniansl_SI Slovenian (Slovenia)sq Albaniansq_AL Albanian (Albania)sr Serbiansr_YU Serbian (Yugoslavia)sv Swedishsv_SE Swedish (Sweden)th Thaith_TH Thai (Thailand)tr Turkishtr_TR Turkish (Turkey)uk Ukrainianuk_UA Ukrainian (Ukraine)zh Chinesezh_CN Chinese (China)zh_HK Chinese (Hong Kong)zh_TW Chinese (Taiwan)======System property========-- listing properties --java.runtime.name=Java(TM) 2 Runtime Environment, Stand...sun.boot.library.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...java.vm.version=1.3.0_02java.vm.vendor=Sun Microsystems Inc.java.vendor.url=http://java.sun.com/path.separator=;java.vm.name=Java HotSpot(TM) Client VMfile.encoding.pkg=sun.iojava.vm.specification.name=Java Virtual Machine Specificationuser.dir=D:\java\src\char_testjava.runtime.version=1.3.0_02java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironmentos.arch=x86java.io.tmpdir=D:\TEMP\line.separator=java.vm.specification.vendor=Sun Microsystems Inc.java.awt.fonts=os.name=Windows 98java.library.path=C:\WINDOWS;.;C:\WINDOWS\SYSTEM;C:\WIN...java.specification.name=Java Platform API Specificationjava.class.version=47.0os.version=4.90user.home=C:\WINDOWSuser.timezone=Asia/Shanghaijava.awt.printerjob=sun.awt.windows.WPrinterJobfile.encoding=Cp1252
java.specification.version=1.3
user.name=Sicci
java.class.path=d:\java\classes
java.vm.specification.version=1.0
java.home=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_02
user.language=en
java.specification.vendor=Sun Microsystems Inc.
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.3.0_02
java.ext.dirs=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
sun.boot.class.path=C:\PROGRAM FILES\JavaSOFT\JRE\1.3.0_0...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
user.region=GB
sun.cpu.isalist=pentium i486 i386
结论1:
JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关。所以当设置成相同的LOCALE时,Linux和Windows下的缺省编码方式是没有区别的(可以认为cp1252=ISO-8859-1都是一样的西文编码方式,只包含255以下的拉丁字符),因此后面的测试2我只列出了GNU/Linux下LOCALE分别设置成zh_CN和en_US的测试结果输出。以下测试如果在Windows下分别按照不同的区域和字符集设置后试验的输出是一样的。
试验2:Java的输入输出过程中的字节流到字符流的转换过程
通过这个HelloUnicode.java程序,演示说明"Hello world 世界你好"这个字符串(16个字符)在不同缺省系统编码方式下的处理效果。在编码/解码的每个步骤之后,都打印出了相应字符串每个字符(Charactor)的byte值,short值和所在的UNICODE区间。
LANG=en_US LC_ALL=en_US LANG=zh_CN LC_ALL=zh_CN.GBK
========testing1: write hello world to files========[test 1-1]: with system default encoding=ISO-8859-1string=Hello world 世界你好 length=20char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATINchar[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATINchar[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATINchar[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATINchar[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATINchar[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[12]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[13]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[14]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[15]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[16]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[17]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[18]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[19]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT第1步:在英文编码环境下,虽然屏幕上正确的显示了中文,但实际上它打印的是“半个”汉字,将结果写入第1个文件 hello.orig.html
[test 1-2]: getBytes with platform default encoding and decoding as gb2312:
string=Hello world ???? length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='?' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='?' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='?' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='?' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
按系统缺省编码重新变成字节流,然后按照GB2312方式解码,这里虽然打印出的是问号(因为当前的英文环境下系统对于255以上的字符是不知道用什么字符表示的,因此全部用?显示)但从相应的UNICODE MAPPING和SHORT值我们可以知道字符是正确的中文但下一步的写入第2个文件html.gb2312.html,没有指定编码方式(按系统缺省的ISO-8859-1编码方式),因此从后面的测试2-2读取的结果是真的'?'了
[test 1-3]: convert string to UTF8
string=Hello world 涓栫晫浣犲ソ length=24
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='? byte=-28 \uFFFFFFE4 short=228 \uE4 LATIN_1_SUPPLEMENT
char[13]='? byte=-72 \uFFFFFFB8 short=184 \uB8 LATIN_1_SUPPLEMENT
char[14]='? byte=-106 \uFFFFFF96 short=150 \u96 LATIN_1_SUPPLEMENT
char[15]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENT
char[16]='? byte=-107 \uFFFFFF95 short=149 \u95 LATIN_1_SUPPLEMENT
char[17]='? byte=-116 \uFFFFFF8C short=140 \u8C LATIN_1_SUPPLEMENT
char[18]='? byte=-28 \uFFFFFFE4 short=228 \uE4 LATIN_1_SUPPLEMENT
char[19]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENT
char[20]='? byte=-96 \uFFFFFFA0 short=160 \uA0 LATIN_1_SUPPLEMENT
char[21]='? byte=-27 \uFFFFFFE5 short=229 \uE5 LATIN_1_SUPPLEMENT
char[22]='? byte=-91 \uFFFFFFA5 short=165 \uA5 LATIN_1_SUPPLEMENT
char[23]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENT
第3个试验,将字符流按照UTF8方式编码后,写入第3个测试文件hello.utf8.html,我们可以看到UTF8对英文没有影响,但对于其他文字使用了3字节编码方式,因此比GB2312编码方式的存储要大50%,
========Testing2: reading and decoding from files========
[test 2-1]: read hello.orig.html: decoding with system default encoding
string=Hello world 世界你好 length=20
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENT
char[13]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENT
char[14]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENT
char[15]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENT
char[16]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENT
char[17]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENT
char[18]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENT
char[19]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT
按系统从中间存储hello.orig.html文件中读取相应文件,虽然是按字节方式(半个“字”)读取的,但由于能完整的还原,因此输出显示没有错误。其实PHP等应用很少出现字符集问题其实就是这个原因,全程都是按字节流方式处理,很好的还原了输入,但这样处理的同时也失去了对字符的控制
[test 2-2]: read hello.gb2312.html: decoding as GB2312
string=Hello world ???? length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[13]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[14]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
char[15]='?' byte=63 \u3F short=63 \u3F BASIC_LATIN
最惨的就是输出的时候这些'?'真的是问号char(63)了,数据如果是这样就真的没救了
[test 2-3]: read hello.utf8.html: decoding as UTF8
string=Hello world ???? length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='?' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='?' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='?' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='?' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
great! 字符虽然显示为'?',但实际上字符的解码是正确的,从相应的UNICODE MAPPING就可以看的出来。
========Testing1: write hello world to files========[test 1-1]: with system default encoding=GBKstring=Hello world 世界你好 length=16char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATINchar[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATINchar[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATINchar[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATINchar[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATINchar[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATINchar[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATINchar[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATINchar[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS注意:在新的语言环境中做以上测试需要将源程序重新编译,最早的字节流到字符流的解码过程从JavaC编译源文件就开始了,这个测试和刚才最大的不同在于源文件中的“世界你好”这4个字是否按中文编码方式编译导程序里的,而不是按字节方式编译成8个字符(实际上对应的是8个字节)在程序里。
[test 1-2]: getBytes with platform default encoding and decoding as gb2312:
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
在中文环境下,解码和上面缺省的编码是一致的,因此输出一致
[test 1-3]: convert string to UTF8
string=Hello world 涓栫晫浣犲ソ length=18
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='涓' byte=-109 \uFFFFFF93 short=28051 \u6D93 CJK_UNIFIED_IDEOGRAPHS
char[13]='栫' byte=43 \u2B short=26667 \u682B CJK_UNIFIED_IDEOGRAPHS
char[14]='晫' byte=107 \u6B short=26219 \u666B CJK_UNIFIED_IDEOGRAPHS
char[15]='浣' byte=99 \u63 short=28003 \u6D63 CJK_UNIFIED_IDEOGRAPHS
char[16]='犲' byte=-78 \uFFFFFFB2 short=29362 \u72B2 CJK_UNIFIED_IDEOGRAPHS
char[17]='ソ' byte=-67 \uFFFFFFBD short=12477 \u30BD KATAKANA
其实我们用于测试的终端窗口就是一个GBK字符集的应用,这个输出其实都是把UNICODE按GBK字符集解码的效果。
========Testing2: reading and decoding from files========
[test 2-1]: read hello.orig.html: decoding with system default encoding
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
[test 2-2]: read hello.gb2312.html: decoding as GB2312
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
[test 2-3]: read hello.utf8.html: decoding as UTF8
string=Hello world 世界你好 length=16
char[0]='H' byte=72 \u48 short=72 \u48 BASIC_LATIN
char[1]='e' byte=101 \u65 short=101 \u65 BASIC_LATIN
char[2]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[3]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[4]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[5]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[6]='w' byte=119 \u77 short=119 \u77 BASIC_LATIN
char[7]='o' byte=111 \u6F short=111 \u6F BASIC_LATIN
char[8]='r' byte=114 \u72 short=114 \u72 BASIC_LATIN
char[9]='l' byte=108 \u6C short=108 \u6C BASIC_LATIN
char[10]='d' byte=100 \u64 short=100 \u64 BASIC_LATIN
char[11]=' ' byte=32 \u20 short=32 \u20 BASIC_LATIN
char[12]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHS
char[13]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHS
char[14]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHS
char[15]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
结论:如果后台数据采用UNICODE方式的存储然后根据需要指定字符集编码、解码方式,则应用几乎可以不受前端应用所处环境字符集设置的影响
试验2的一些结论:
所有的应用都是按照字节流=>字符流=>字节流方式进行的处理的:
byte_stream ==[input decoding]==> unicode_char_stream ==[output encoding]==> byte_stream;
在Java字节流到字符流(或者反之)都是含有隐含的解码处理的(缺省是按照系统缺省编码方式);
最早的字节流解码过程从javac的代码编译就开始了;
Java中的字符character存储单位是双字节的UNICODE;
试验3:WEB应用中的输入输出中的编码问题:Java是为做国际化应用设计的,Servlet应根据浏览器语言设置自动切换字符集配置
首先一个概念:即使是基于Java的WEB应用,在服务器和客户端之间传递的仍然是字节流,比如我从一个中文客户端的浏览器表单中提交“世界你好”这4个中文字到服务器时:首先浏览器按照GBK方式编码成字节流CA C0 BD E7 C4 E3 BA C3,然后8个字节按照URLEncoding的规范转成:%CA%C0%BD%E7%C4%E3%BA%C3,服务器端的Servlet接收到请求后应该按什么解码处理,输出时又应该按什么方式编码行字节流呢?
在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:
当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK:
//auto detect broswer's languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }
输出为:
'世界你好' length=4ServletRequest's Charset Encoding = GBK ServletResponse's Charset Encoding = GBK char[0]='世' byte=22 \u16 short=19990 \u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]='界' byte=76 \u4C short=30028 \u754C CJK_UNIFIED_IDEOGRAPHSchar[2]='你' byte=96 \u60 short=20320 \u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]='好' byte=125 \u7D short=22909 \u597D CJK_UNIFIED_IDEOGRAPHS
再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:
'世界你好' length=8ServletRequest's Charset Encoding = null ServletResponse's Charset Encoding = ISO-8859-1 char[0]='? byte=-54 \uFFFFFFCA short=202 \uCA LATIN_1_SUPPLEMENTchar[1]='? byte=-64 \uFFFFFFC0 short=192 \uC0 LATIN_1_SUPPLEMENTchar[2]='? byte=-67 \uFFFFFFBD short=189 \uBD LATIN_1_SUPPLEMENTchar[3]='? byte=-25 \uFFFFFFE7 short=231 \uE7 LATIN_1_SUPPLEMENTchar[4]='? byte=-60 \uFFFFFFC4 short=196 \uC4 LATIN_1_SUPPLEMENTchar[5]='? byte=-29 \uFFFFFFE3 short=227 \uE3 LATIN_1_SUPPLEMENTchar[6]='? byte=-70 \uFFFFFFBA short=186 \uBA LATIN_1_SUPPLEMENTchar[7]='? byte=-61 \uFFFFFFC3 short=195 \uC3 LATIN_1_SUPPLEMENT
虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)
http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/ServletResponse.html#setContentType()
以前能够配置让一个WEB应用能够在GBK方式编码的中文Windows2000服务器上和按ISO-8859-1方式编码的GNU/Linux上都能够正确的显示中文一直让我迷惑了很久。我仔细想了一下,后来终于想明白了,在一个国际化的应用中:ServletRequest和ServletResponse的编码/解码方式的确不应该根据服务器设置成固定的字符集,而应该是面向客户端语言环境进行输入/输出编码方式的自适应。一个按照国际化规范设计的WEB应用中:
在Servlet的源代码中尽量不要有中文:因为在MVC模式中,Servlet主要是控制器(C)的角色,因此,应该通过ResourceBundle机制由Servlet控制转向到相应的显示器(JSP或者XSLT)中,所以应该将与本地界面语言相关的界面显示的部分从Servlet和后台的模块中完全剥离出来,放到相应的ResourceBundle文件中或者XSLT文件中。这样源程序里完全是英文,编译时完全不需要考虑字符集的问题。
如果Servlet实在需要包含中文,则需要设置应用服务器的Javac编译选项,加上-encoding选项成系统缺省的字符集,如果把用中文编写的字符按照英文方式解码编译,然后再按照英文方式输出,虽然结果表面正确,实际上都成了面向“字节”编程。
在Servlet层,应该像GOOGLE搜索引擎那样,设计成能够根据客户端浏览器的语言环境自适应输出,为了判断浏览器的语言Servlet中应该有类似以下的代码:
public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { //从HTTP请求的头信息中获取客户端的语言设置 String clientLanguage = req.getHeader("Accept-Language"); //简体中文浏览器 if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); } //繁体中文浏览器 else if ( clientLanguage.equals("zh-tw") ) { req.setCharacterEncoding("BIG5"); res.setContentType("text/html; charset=BIG5"); } //日文浏览器 else if ( clientLanguage.equals("jp") ) { req.setCharacterEncoding("SJIS"); res.setContentType("text/html; charset=SJIS"); } //缺省认为是英文浏览器 else { req.setCharacterEncoding("ISO-8859-1"); res.setContentType("text/html; charset=ISO-8859-1"); } ... //设置好request的解码方式和response的编码方式后,进行后续的操作。 //比如再转向到HelloWorld.gbk.jsp HelloWorld.big5.jsp HelloWorld.jis.jsp等 }
而SERVLET缺省将字符集设置为ISO-8859-1也许是标准制定者认为英文的浏览器占大多数吧(而且按照ISO-8859-1方式输出界面往往也是正确的)。
结论:
过以上几个Java试验程序得出的一些结论:
Java环境是基于操作系统上的一个虚拟机应用,因此,如果操作系统遵循国际化规范:JVM的缺省编码方式可以通过修改操作系统的LOCALE设置实现。对于一个Java应用来说,只要将LINUX的缺省编码方式设置成GBK,其文字编码处理应该和中文Windows平台上的表现是一致的。
redhat 6.X使用linux内核的是基于glibc2.1.X,不支持中文LOCALE,因此无法通过改变LOCALE设置改变JVM的缺省编码方式,linux内核2.4开始基于glibc.2.2.x,对中文LOCALE有了比较好的支持。
不同的JVM对字符集的支持程度不同:
比如:IBM的JVM1.3.0开始支持GB18030,SUN的JVM从1.4开始支持GB18030
正确的编码方式不一定表示能正确的显示,正确的显示还要需要相应的前端显示系统(字库)的支持
但对于Linux上的服务应用来说,往往只要能确认字符正确的按照指定的方式编码就够了
如果应用的是基于UNICODE的编码方式处理并使用UTF8字符集做集中存储,这样最便于根据客户端语言环境做本地化输出;
根据以上结论,设计一个适应多语言环境的应用,可以考虑一下2个应用处理模式:
(客户端应用或本地化应用)根据LOCALE,让Java应用根据系统LOCALE的缺省的字符集设置进行切换,按系统缺省的字符集进行编码解码,减少应用在编码处理上的复杂程度。
输入字节流 ==>按系统语言字符集设置将字节流解码==> UNICODE处理 ==> 按系统语言字符集设置将UNICODE编码成字节流 ==> 输出字节流
(服务器端或跨语言平台应用):在应用的最外端:数据输入输出判断用户语言环境,核心按照UNICODE方式处理存储。可以把各种区域性的字符集(GB2312 BIG5)看成是UNICODE的一个子集。UNICODE存储的数据可以方便的转换成任意字符集。
应用使用UTF8方式存储虽然要增加了存储空间,但也可以大大简化前端应用本地化(i10n)的复杂程度。
简体中文输入 繁体中文输入 简体中文输出 繁体中文输出 \ / \ / 判断用户语言环境:解码 判断用户语言环境:编码 \ / 中间处理过程:UNICODE | UTF8编码存储
随着UNICODE被愈来愈多的系统和平台支持:Python Perl Glibc等,但我们应该珍惜一开始就按照国际化规范设计Java,并将其和新发展起来的XML规范相配合,相信符合国际化规范的应用设计从长远来看会展现出更多的优势。
TODO:
数据库应用中的字符集问题试验:MySQL Oracle JDBC
参考文档:
Java的国际化设计
http://java.sun.com/docs/books/tutorial/i18n/index.html
Linux 国际化本地化和中文化
http://www.linuxforum.net/doc/i18n-new.html
Linux 程序员必读:中文化与GB18030标准
http://www.ccidnet.com/tech/os/2001/07/31/58_2811.html
Unicode FAQ
http://www.cl.cam.ac.uk/~mgk25/unicode.html
http://www.linuxforum.net/books/UTF-8-Unicode.html (中文版)
Java 编程技术中汉字问题的分析及解决
http://www-900.ibm.com/developerWorks/cn/java/java_chinese/index.shtml
汉字的编码方式:
http://www.unihan.com.cn/cjk/ana17.htm
不同版本的JVM支持的编码方式
http://java.sun.com/j2se/1.3/docs/guide/intl/encoding.doc.html
http://java.sun.com/j2se/1.4/docs/guide/intl/encoding.doc.html
附录:
A. The Unicode 2.0 Character Set
Characters
Description
\u0000 - \u1FFF
Alphabets
\u0020 - \u007F
Basic Latin
\u0080 - \u00FF
Latin-1 supplement
\u0100 - \u017F
Latin extended-A
\u0180 - \u024F
Latin extended-B
\u0250 - \u02AF
IPA extensions
\u02B0 - \u02FF
Spacing modifier letters
\u0300 - \u036F
Combining diacritical marks
\u0370 - \u03FF
Greek
\u0400 - \u04FF
Cyrillic
\u0530 - \u058F
Armenian
\u0590 - \u05FF
Hebrew
\u0600 - \u06FF
Arabic
\u0900 - \u097F
Devanagari
\u0980 - \u09FF
Bengali
\u0A00 - \u0A7F
Gurmukhi
\u0A80 - \u0AFF
Gujarati
\u0B00 - \u0B7F
Oriya
\u0B80 - \u0BFF
Tamil
\u0C00 - \u0C7F
Telugu
\u0C80 - \u0CFF
Kannada
\u0D00 - \u0D7F
Malayalam
\u0E00 - \u0E7F
Thai
\u0E80 - \u0EFF
Lao
\u0F00 - \u0FBF
Tibetan
\u10A0 - \u10FF
Georgian
\u1100 - \u11FF
Hangul Jamo
\u1E00 - \u1EFF
Latin extended additional
\u1F00 - \u1FFF
Greek extended
\u2000 - \u2FFF
Symbols and punctuation
\u2000 - \u206F
General punctuation
\u2070 - \u209F
Superscripts and subscripts
\u20A0 - \u20CF
Currency symbols
\u20D0 - \u20FF
Combining diacritical marks for symbols
\u2100 - \u214F
Letterlike symbols
\u2150 - \u218F
Number forms
\u2190 - \u21FF
Arrows
\u2200 - \u22FF
Mathematical operators
\u2300 - \u23FF
Miscellaneous technical
\u2400 - \u243F
Control pictures
\u2440 - \u245F
Optical character recognition
\u2460 - \u24FF
Enclosed alphanumerics
\u2500 - \u257F
Box drawing
\u2580 - \u259F
Block elements
\u25A0 - \u25FF
Geometric shapes
\u2600 - \u26FF
Miscellaneous symbols
\u2700 - \u27BF
Dingbats
\u3000 - \u33FF
CJK auxiliary
\u3000 - \u303F
CJK symbols and punctuation
\u3040 - \u309F
Hiragana
\u30A0 - \u30FF
Katakana
\u3100 - \u312F
Bopomofo
\u3130 - \u318F
Hangul compatibility Jamo
\u3190 - \u319F
Kanbun
\u3200 - \u32FF
Enclosed CJK letters and months
\u3300 - \u33FF
CJK compatibility
\u4E00 - \u9FFF
CJK unified ideographs: Han characters used in China, Japan, Korea, Taiwan, and Vietnam
\uAC00 - \uD7A3
Hangul syllables
\uD800 - \uDFFF
Surrogates
\uD800 - \uDB7F
High surrogates
\uDB80 - \uDBFF
High private use surrogates
\uDC00 - \uDFFF
Low surrogates
\uE000 - \uF8FF
Private use
\uF900 - \uFFFF
Miscellaneous
\uF900 - \uFAFF
CJK compatibility ideographs
\uFB00 - \uFB4F
Alphabetic presentation forms
\uFB50 - \uFDFF
Arabic presentation forms-A
\uFE20 - \uFE2F
Combing half marks
\uFE30 - \uFE4F
CJK compatibility forms
\uFE50 - \uFE6F
Small form variants
\uFE70 - \uFEFE
Arabic presentation forms-B
\uFEFF
Specials
\uFF00 - \uFFEF
Halfwidth and fullwidth forms
\uFFF0 - \uFFFF
Specials
原文出处:<a href="http://www.chedong.com/tech/hello_unicode.html">http://www.chedong.com/tech/hello_unicode.html</a>
<<返回
<<返回首页
发表评论
-
JAVA字符集和字符串的编码
2006-10-20 19:17 4374先提出问题: 都知道,windows XP 的默认编码方式 ... -
java增补字符
2006-10-20 19:16 1496摘要 本文介绍 Java 平台支持增补字符的方式。增补字符是 ... -
Linux下GB2313与UTF8的相互转换
2006-10-20 19:16 2416int code_convert(char *from_cha ... -
Unicode 问答集
2006-10-20 19:15 1129问:什么是Unicode? 答 ... -
谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
2006-10-20 19:14 1116这是一篇程序员写给程 ... -
关于utf-8,unicode字符集
2006-10-20 19:12 2167utf-8是unicode的一个新的编码标准,其实unicod ... -
java编码中的一些经验和教训
2006-10-20 19:11 889这几天集中时间重拾388备份文件格式研究,使用的工具主要是ne ...
相关推荐
《林信良Java学习笔记》是一本深受程序员喜爱的Java学习资源,尤其因其繁体字版,对于中文读者来说,提供了更为亲切的阅读体验。这本书深入浅出地讲解了Java编程语言的基础知识和高级特性,旨在帮助初学者快速掌握...
Java学习笔记 1、连接数据库步骤 2、不同数据库的驱动程序和连接字符串 3、连接数据库常见问题 4、B/S结构和C/S结构的区别 5、如何处理中文乱码问题 6、使用JavaMail发送注册验证邮件 7、不安全的用户名密码验证 8、...
### Java学习笔记要点 #### 一、了解Java ##### 1.1 Java的起源与发展历程 - **起源**: Java 最初是由 Sun 公司在 Green Project 中为了开发 Star7 应用程序而创建的一种编程语言。 - **命名**: 语言的名字来源于 ...
【Java学习笔记整理】 Java是一种广泛使用的编程语言,它不仅是一种语言,还是一个软件开发平台和运行环境。Java分为三个主要版本:Java标准版(JSE)、Java缩微版(JME)和Java企业版(JEE)。JSE主要用于桌面应用...
Java中的正则表达式支持广泛的标准和特性,是进行文本处理任务的理想选择之一。本文将通过一系列示例来介绍Java正则表达式的基础知识及其应用场景。 #### 二、Java正则表达式基本语法 在Java中使用正则表达式前,...
### Java学习笔记——Java与Hibernate入门精要 #### 一、Java学习笔记概述 本学习笔记旨在帮助初学者系统地掌握Java语言的基础知识,并通过实际案例深入理解Hibernate框架的应用。通过对核心概念和技术点的详细解释...
这份“Java JDK 8学习笔记”涵盖了这一版本的关键知识点,对于初学者和进阶者都是宝贵的参考资料。 1. **lambda表达式**:JDK 8引入了lambda表达式,它简化了函数式编程,使得处理集合数据时的代码更加简洁。Lambda...
### Java学习笔记知识点详解 #### 第一章:Linux简介与Java环境配置 ##### Linux与Java关系及计算机分类 - **Linux用途**:主要用于服务端,是进行服务端开发的首选操作系统之一。 - **计算机分类**: - **PC机*...
学习《实用Java》中文版,不仅可以掌握Java编程的核心技能,还能了解到实际开发中的最佳实践。通过不断地实践和阅读笔记,读者将能够逐步提升自己的编程能力和解决问题的能力,成为一名熟练的Java开发者。
《良葛格Java 学习笔记(繁体全)》是一部详尽的Java学习资源,旨在帮助初学者和进阶者深入理解Java编程语言。笔记内容涵盖了从基础语法到高级特性的广泛领域,以繁体中文呈现,适合中文阅读习惯的用户。下面将对其中...
【JAVA-JSP学习笔记】 1. **JSP中去除字符串空格**:在JSP中,我们可以使用`String.trim()`方法来去除字符串两端的空格,如果需要去除所有空格,可以使用`String.replaceAll("\\s", "")`。 2. **JSP页面间参数传递...
在IT领域,特别是Java编程的学习过程中,"JAVA夜未眠,thinkingJAVA和学习笔记"这一主题涵盖了许多核心概念和实践技巧。以下是对这些资源的详细解释: 首先,"Java夜未眠"可能指的是一个深入探讨Java编程的书籍或...
在本学习笔记中,博主孙风涛详细记录了张孝祥讲师主讲的《Java邮件开发》课程,涵盖了电子邮件基础知识、邮件协议、JavaMail API的使用、邮件内容的组织、编码及发送过程,以及在Web应用中集成邮件功能的实践。...
在这些学习笔记中,你可以深入理解Java的核心概念,包括语法、数据类型、控制结构、类与对象,以及异常处理等。Java_笔记整理部分可能详细介绍了这些基本概念,并提供了实际编程中的应用示例。 CSS(Cascading ...
### Selenium Java 学习笔记知识点总结 #### 一、Selenium简介与安装配置 - **Selenium概述**:Selenium 是一套完整的Web应用程序测试工具,主要用于自动化Web应用测试,能够模拟用户行为,支持多种浏览器环境。 - ...
- **Java SE API 使用**:掌握字符串处理、异常处理、集合框架、输入输出流、多线程等基础知识。 - **在线资源**:访问官方文档 (`http://java.sun.com/javase/6/docs/api/index.html`) 获取最新 API 文档。 - **...
在Java学习的第二天,我们深入理解了JRE的构成,它是Java运行环境,包含了JVM(Java虚拟机)和其他必要的类库文件。这些类库文件,如`tools.jar`,对于Java程序的运行至关重要。Java中,我们常用`jar`命令来打包和...
Java编程语言的基础知识在给定的学习笔记中得到了详细介绍。以下是其中关键知识点的详细解析: 1. 注释(Comments): - 单行注释:以`//`开头,一行内描述内容。 - 多行注释:以`/*`开始,以`*/`结束,可跨多行...
Java Web 学习笔记主要涉及了文件上传这一关键知识点,这是在开发Web应用程序时常见的功能,比如用户上传头像、图片或附件等。文件上传在HTML表单中通过特定的方式实现,包括以下几点: 1. **表单提交方式**:为了...