Java,字符串编码,ASCII、GBK、Unicode、UTF-8、UTF-16和UTF-32
字符串编码
ASCII和非ASCII
ASCII,American Standard Code for Information Interchange(美国信息交换标准代码),是基于拉丁字母的,主要用于显示现代英语和其他西欧语言,一个字节有8个二进制位(bit),可以表示256(2^8)种不同的状态,即256个符号,从0000000到11111111。ASCII码一共规定了128个字符的编码,如大写的字母A是65(二进制01000001),这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。
GB2312和GBK
GB2312或GB 2312-80是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,又称 GB 0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持 GB 2312。
GBK即汉字内码扩展规范,K为汉语拼音 Kuo Zhan(扩展)中“扩”字的声母。英文全称Chinese Internal Code Specification。GBK 共收入21886个汉字和图形符号,包括:GB 2312 中的全部汉字、非汉字符号。BIG5 中的全部汉字。与 ISO 10646相应的国家标准 GB 13000 中的其它 CJK 汉字,以上合计 20902 个汉字。其它汉字、部首、符号,共计 984 个。GBK 向下与 GB 2312 完全兼容,向上支持 ISO 10646 国际标准,在前者向后者过渡过程中起到的承上启下的作用。
Unicode(统一码、万国码、单一码)
计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。
Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。目前的Unicode字符分为17组编排,0x0000至0x10FFFF,每组称为平面(Plane),而每平面拥有65536个码位,共1114112个,然而目前只用了少数平面。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。
通用字符集(Universal Character Set, UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。
UTF-8
UTF-8以字节为单位对Unicode进行编码,UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码,由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。UTF-8用1到6个字节编码Unicode字符。用在网页上可以统一页面显示中文简体繁体及其它语言(如英文,日文,韩文)。
UTF-16
UTF-16编码以16位无符号整数为单位。UTF-16是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为 "storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。
UTF-16是Unicode的其中一个使用方式。 UTF是Unicode TransferFormat,即把Unicode转做某种格式的意思。
它定义于ISO/IEC 10646-1的附录Q,而RFC2781也定义了相似的做法。
在Unicode基本多文种平面定义的字符(无论是拉丁字母、汉字或其他文字或符号),一律使用2字节储存。而在辅助平面定义的字符,会以代理对(surrogate pair)的形式,以两个2字节的值来储存。
UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存,但UTF-16却无法兼容于ASCII编码。
UTF-32
UTF-32编码以32位无符号整数为单位。Unicode的UTF-32编码就是其对应的32位无符号整数。UTF-32 (或 UCS-4)是一种将Unicode字符编码的协定,对每一个Unicode码位使用恰好32位元,其它的Unicode transformation formats则使用不定长度编码,因为UTF-32对每个字符都使用4字节,就空间而言,是非常没有效率的。特别地,非基本多文种平面的字符在大部分文件中通常很罕见,以致于它们通常被认为不存在占用空间大小的讨论,使得UTF-32通常会是其它编码的二到四倍,虽然每一个码位使用固定长定的字节看似方便,它并不如其它Unicode编码使用得广泛。
操作系统支持的编码
/**
* 操作系统支持的编码
*/
public class SupportEncodeTest {
public static void main(String[] args) {
Map availMap = Charset.availableCharsets();
Set keys = availMap.keySet();
for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
System.out.println(iter.next());
}
}
}
Java字符串的编码
import java.io.FileWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
/**
* Java字符串的编码
*/
public class EncodeTest {
/**
* @param args
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws Exception {
// Java中字符仅以一种形式存在,那就是Unicode.
String str = "中";
String str2 = "\u4E2D";
System.out.println(str.equals(str2));
// Java中的字符是以Unicode的形式表达的,转字节数组后变成GBK编码,与操作系统一致
System.out.println(compareEncode(str, "GBK"));
System.out.println(compareEncode(str, "Unicode"));
System.out.println(compareEncode(str, "UTF-16"));
System.out.println(compareEncode(str, "UTF-16BE"));
System.out.println(compareEncode(str, "UTF-16LE"));
// 获取默认编码,与操作系统有关系,默认是中文GBK编码
System.out.println("Default Charset IS: " + Charset.defaultCharset());
System.out.println("Default Charset IS: " + System.getProperty("file.encoding"));
FileWriter filewriter = new FileWriter("out");
String encname = filewriter.getEncoding();
filewriter.close();
System.out.println("Default Charset IS: " + encname);
}
/**
* @param str
* @param encode
* @return
* @throws UnsupportedEncodingException
*/
private static boolean compareEncode(String str, String encode)
throws UnsupportedEncodingException {
byte[] bt = str.getBytes();
byte[] bt2 = str.getBytes(encode);
if (bt.length != bt2.length) {
System.out.println(bt.length);
System.out.println(bt2.length);
} else {
boolean result = true;
for (int i = 0; i < bt.length; i++) {
if (bt[i] != bt2[i]) {
result = false;
}
}
return result;
}
return false;
}
}
Java字符串编码转换
import java.io.UnsupportedEncodingException;
/**
* Java字符串编码转换
*/
public class ChangeCharset {
/**
* 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块
*/
public static final String US_ASCII = "US-ASCII";
/**
* ISO 拉丁字母表 No.1,也叫作 ISO-LATIN-1
*/
public static final String ISO_8859_1 = "ISO-8859-1";
/**
* 8 位 UCS 转换格式
*/
public static final String UTF_8 = "UTF-8";
/**
* 16 位 UCS 转换格式,Big Endian(最低地址存放高位字节)字节顺序
*/
public static final String UTF_16BE = "UTF-16BE";
/**
* 16 位 UCS 转换格式,Little-endian(最高地址存放低位字节)字节顺序
*/
public static final String UTF_16LE = "UTF-16LE";
/**
* 16 位 UCS 转换格式,字节顺序由可选的字节顺序标记来标识
*/
public static final String UTF_16 = "UTF-16";
/**
* 中文超大字符集
*/
public static final String GBK = "GBK";
/**
* 将字符编码转换成US-ASCII码
*/
public String toASCII(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, US_ASCII);
}
/**
* 将字符编码转换成ISO-8859-1码
*/
public String toISO_8859_1(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, ISO_8859_1);
}
/**
* 将字符编码转换成UTF-8码
*/
public String toUTF_8(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, UTF_8);
}
/**
* 将字符编码转换成UTF-16BE码
*/
public String toUTF_16BE(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, UTF_16BE);
}
/**
* 将字符编码转换成UTF-16LE码
*/
public String toUTF_16LE(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, UTF_16LE);
}
/**
* 将字符编码转换成UTF-16码
*/
public String toUTF_16(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, UTF_16);
}
/**
* 将字符编码转换成GBK码
*/
public String toGBK(String str) throws UnsupportedEncodingException {
return this.changeCharset(str, GBK);
}
/**
* 字符串编码转换的实现方法
*
* @param str 待转换编码的字符串
* @param newCharset 目标编码
* @return
* @throws UnsupportedEncodingException
*/
public String changeCharset(String str, String newCharset)
throws UnsupportedEncodingException {
if (str != null) {
// 用默认字符编码解码字符串。
byte[] bs = str.getBytes();
// 用新的字符编码生成字符串
return new String(bs, newCharset);
}
return null;
}
/**
* 字符串编码转换的实现方法
*
* @param str 待转换编码的字符串
* @param oldCharset 原编码
* @param newCharset 目标编码
* @return
* @throws UnsupportedEncodingException
*/
public String changeCharset(String str, String oldCharset, String newCharset)
throws UnsupportedEncodingException {
if (str != null) {
// 用旧的字符编码解码字符串。解码可能会出现异常。
byte[] bs = str.getBytes(oldCharset);
// 用新的字符编码生成字符串
return new String(bs, newCharset);
}
return null;
}
/**
* @param args
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws UnsupportedEncodingException {
ChangeCharset changeCharset = new ChangeCharset();
String str = "This is a 中文的 String!";
System.out.println("str: " + str);
String gbk = changeCharset.toGBK(str);
System.out.println("转换成GBK码: " + gbk);
System.out.println();
String ascii = changeCharset.toASCII(str);
System.out.println("转换成US-ASCII码: " + ascii);
gbk = changeCharset.changeCharset(ascii, ChangeCharset.US_ASCII, ChangeCharset.GBK);
System.out.println("再把ASCII码的字符串转换成GBK码: " + gbk);
System.out.println();
String iso88591 = changeCharset.toISO_8859_1(str);
System.out.println("转换成ISO-8859-1码: " + iso88591);
gbk = changeCharset.changeCharset(iso88591, ChangeCharset.ISO_8859_1, ChangeCharset.GBK);
System.out.println("再把ISO-8859-1码的字符串转换成GBK码: " + gbk);
System.out.println();
String utf8 = changeCharset.toUTF_8(str);
System.out.println("转换成UTF-8码: " + utf8);
gbk = changeCharset.changeCharset(utf8, ChangeCharset.UTF_8, ChangeCharset.GBK);
System.out.println("再把UTF-8码的字符串转换成GBK码: " + gbk);
System.out.println();
String utf16be = changeCharset.toUTF_16BE(str);
System.out.println("转换成UTF-16BE码:" + utf16be);
gbk = changeCharset.changeCharset(utf16be, ChangeCharset.UTF_16BE, ChangeCharset.GBK);
System.out.println("再把UTF-16BE码的字符串转换成GBK码: " + gbk);
System.out.println();
String utf16le = changeCharset.toUTF_16LE(str);
System.out.println("转换成UTF-16LE码:" + utf16le);
gbk = changeCharset.changeCharset(utf16le, ChangeCharset.UTF_16LE, ChangeCharset.GBK);
System.out.println("再把UTF-16LE码的字符串转换成GBK码: " + gbk);
System.out.println();
String utf16 = changeCharset.toUTF_16(str);
System.out.println("转换成UTF-16码:" + utf16);
gbk = changeCharset.changeCharset(utf16, ChangeCharset.UTF_16LE, ChangeCharset.GBK);
System.out.println("再把UTF-16码的字符串转换成GBK码: " + gbk);
String s = new String("中文".getBytes("UTF-8"), "UTF-8");
System.out.println(s);
}
}
Java Unicode
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.UnsupportedEncodingException;
public class What21Unicode {
/**
* @param args
*/
public static void main(String[] args) {
// 字符串转换为unicode码:
String result1 = StringEscapeUtils.escapeJava("我们");
System.out.println("result1=" + result1);
// unicode码转为字符串:
String result2 = StringEscapeUtils.unescapeJava("\u6211\u4EEC");
System.out.println("result2=" + result2);
// 字符
String str = "我们";
System.out.println(str);
// unicode编码字符
String unicode = "\u6211\u4EEC";
System.out.println(unicode);
// 看看该编码
byte[] bytes = null;
try {
bytes = "我们".getBytes("UTF-16BE");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
for (int i = 0; i < bytes.length; i++) {
String cStr = Integer.toHexString(bytes[i]);
if (cStr.length() >= 8) {
cStr = cStr.substring(6, 8);
}
System.out.print(cStr + " ");
}
System.out.println();
}
}