java ucs2转utf8_UCS-2和UTF-8的互相转换

本文详细介绍了UCS-2和UTF-8编码的区别,并提供了Java代码示例,展示如何进行UCS-2到UTF-8的转换。通过理解UTF-8的编码规则,可以高效地进行字符编码的转换。文章通过打印不同字符的UTF-8字节表示,展示了转换的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UCS-2是内码,而UTF-8则是它的实现方式。每一个字节都有8个位,而对于UTF-8来说,每一个字节的前两位尤为重要,按照前两位的不同,一共有四种排列组合:00xxxxxx,01xxxxxx,10xxxxxx,11xxxxxx。

按照UTF-8标准,

(1)所有以0开始的字节,都与原来的ASCII码兼容,也就是说,0xxxxxxx不需要额外转换,就是我们平时用的ASCII码。

(2)所有以10开始的字节,都不是每个UNICODE的第一个字节,都是紧跟着前一位。例如:10110101,这个字节不可以单独解析,必须通过前一个字节来解析,如果前一个也是10开头,就继续前嗍。

(3)所有以11开始的字节,都表示是UNICODE的第一个字节,而且后面紧跟着若干个以10开头的字节。如果是110xxxxx(就是最左边的0的左边有2个1),代表后面还有1个10xxxxxx;如果是1110xxxx(就是最左边的0的左边有3个1),代表后面还有2个10xxxxxx;以此类推,一直到1111110x。

具体的表格如下:

1字节 0xxxxxxx

2字节 110xxxxx 10xxxxxx

3字节 1110xxxx 10xxxxxx 10xxxxxx

4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

(很明显,以11开头的,最左边的0左边有多少个1,那这个UCS的UTF-8的表示长度就有多少个字节)

上面是用6个字节,最多可以表示2 ^ 31个的字符,实际上,只有UCS-4才有这么多的字符,对于UCS-2,仅仅有2 ^ 16个字符,只需要三个字节就可以,也就是说,只需要用到下面的格式:

1字节 0xxxxxxx

2字节 110xxxxx 10xxxxxx

3字节 1110xxxx 10xxxxxx 10xxxxxx

大家可以试一下下面的program,来看看UTF-8的每个字节。

Java代码 icon_copy.gif

packagecom.ray.utf8;

importjava.io.UnsupportedEncodingException;

publicclassUTF8Tester {

privatestaticString toBin(intn) {

StringBuilder b =newStringBuilder();

if(n 0) n +=256;

for(inti =7; i >=0; i--) {

if(1== ((n >> i) &1)) {

b.append('1');

}else{

b.append('0');

}

}

returnb.toString();

}

privatestaticString HEX ="0123456789ABCDEF";

privatestaticString toHex(intn) {

StringBuilder b =newStringBuilder();

if(n 0) n +=256;

b.append(HEX.charAt(n >>4));

b.append(HEX.charAt(n &0x0F));

returnb.toString();

}

privatestaticvoidprintUTF8(charch)throwsUnsupportedEncodingException {

String unicode = toHex(ch >>8) + toHex(ch &0xFF);

String unicodeBin = toBin(ch >>8) +' '+ toBin(ch &0xFF);

String s =""+ ch;

byte[] b = s.getBytes("UTF-8");

String hex ="";

for(inti =0; i

hex += toHex((int) b[i]);

hex +=" ";

}

String bin ="";

for(inti =0; i

bin += toBin((int) b[i]);

bin +=" ";

}

String sf = String.format("U+%s %s : %-8s : %s", unicode, unicodeBin, hex.trim(), bin.trim());

System.out.println(sf);

}

publicstaticvoidmain(String[] args)throwsException {

printUTF8('\u002A');

printUTF8('\u012A');

printUTF8('\u012B');

printUTF8('\u052C');

printUTF8('\u013C');

printUTF8('\uAA2A');

printUTF8('\uFDFD');

}

}package com.ray.utf8;

import java.io.UnsupportedEncodingException;

public class UTF8Tester {

private static String toBin(int n) {

StringBuilder b = new StringBuilder();

if (n < 0) n += 256;

for (int i = 7; i >= 0; i--) {

if (1 == ((n >> i) & 1)) {

b.append('1');

} else {

b.append('0');

}

}

return b.toString();

}

private static String HEX = "0123456789ABCDEF";

private static String toHex(int n) {

StringBuilder b = new StringBuilder();

if (n < 0) n += 256;

b.append(HEX.charAt(n >> 4));

b.append(HEX.charAt(n & 0x0F));

return b.toString();

}

private static void printUTF8(char ch) throws UnsupportedEncodingException {

String unicode = toHex(ch >> 8) + toHex(ch & 0xFF);

String unicodeBin = toBin(ch >> 8) + ' ' + toBin(ch & 0xFF);

String s = "" + ch;

byte[] b = s.getBytes("UTF-8");

String hex = "";

for (int i = 0; i < b.length; i++) {

hex += toHex((int) b[i]);

hex += " ";

}

String bin = "";

for (int i = 0; i < b.length; i++) {

bin += toBin((int) b[i]);

bin += " ";

}

String sf = String.format("U+%s %s : %-8s : %s", unicode, unicodeBin, hex.trim(), bin.trim());

System.out.println(sf);

}

public static void main(String[] args) throws Exception {

printUTF8('\u002A');

printUTF8('\u012A');

printUTF8('\u012B');

printUTF8('\u052C');

printUTF8('\u013C');

printUTF8('\uAA2A');

printUTF8('\uFDFD');

}

}

输出:

U+002A 00000000 00101010 : 2A       : 00101010

U+012A 00000001 00101010 : C4 AA    : 11000100 10101010

U+012B 00000001 00101011 : C4 AB    : 11000100 10101011

U+052C 00000101 00101100 : D4 AC    : 11010100 10101100

U+013C 00000001 00111100 : C4 BC    : 11000100 10111100

U+AA2A 10101010 00101010 : EA A8 AA : 11101010 10101000 10101010

U+FDFD 11111101 11111101 : EF B7 BD : 11101111 10110111 10111101

UCS-2和UTF-8的转换,只涉及到位运算,不需要像GBK般需要查找代码表,所以转换效率很高。

先来说说UTF-8转UCS-2:

(1)对于以0开始的字节,直接在前面部补一个0的字节凑成2个字节(即0xxxxxxx ==> 00000000 0xxxxxxxx);

(2)对于以110开始(110xxxxx)的字节,把后面紧跟着的一个10xxxxxx拿过来,首先在高位字节的左边补5个零,然后把11个“x”放在右边(即110xxxxx 10yyyyyy ==> 00000xxx xxyyyyyy);

(3)对于以1110开始(1110xxxx)的字节,把后面紧跟着的两个10xxxxxx拿过来,数一下,一共有16个“x”,没错,就是把这16个“x”组成两个字节(即1110xxxx 10yyyyyy 10zzzzzz ==> xxxxyyyy yyzzzzzz)。

在来说说UCS-2转UTF-8:

(1)对于不大于0x007F(即00000000 01111111)的,直接把它转成一个字节,变成ASCII;

(2)对于不大于0x07FF(即00000111 11111111)的,转换成两个字节,转换的时候把右边的11位分别放到110xxxxx 10yyyyyy里边,即00000aaa bbbbbbbb ==> 110aaabb 10bbbbbb

(3)剩下的回转换成三个字节,转换的时候也是把16个位分别填写到那三个字节里面,即aaaaaaaa bbbbbbbb ==> 1110aaaa 10aaaabb 10bbcccccc

下面是转换的实现代码:

Java代码 icon_copy.gif

packagecom.ray.utf8;

importjava.io.ByteArrayOutputStream;

importjava.io.UnsupportedEncodingException;

publicclassUtf8Utils {

privatefinalstaticbyteB_10000000 =128-256;

privatefinalstaticbyteB_11000000 =192-256;

privatefinalstaticbyteB_11100000 =224-256;

privatefinalstaticbyteB_11110000 =240-256;

privatefinalstaticbyteB_00011100 =28;

privatefinalstaticbyteB_00000011 =3;

privatefinalstaticbyteB_00111111 =63;

privatefinalstaticbyteB_00001111 =15;

privatefinalstaticbyteB_00111100 =60;

/** Convert from UTF8 bytes to UNICODE character */

publicstaticchar[] toUCS2(byte[] utf8Bytes) {

CharList charList =newCharList();

byteb2 =0, b3 =0;

intub1 =0, ub2 =0;

for(inti =0; i

byteb = utf8Bytes[i];

if(isNotHead(b)) {

// start with 10xxxxxx, skip it.

continue;

}elseif(b >0) {

// 1 byte, ASCII

charList.add((char) b);

}elseif((b & B_11110000) == B_11110000) {

// UCS-4, here we skip it

continue;

}elseif((b & B_11100000) == B_11100000) {

// 3 bytes

b2 = utf8Bytes[i+1];

if(!isNotHead(b2))continue;

i++;

b3 = utf8Bytes[i+1];

if(!isNotHead(b3))continue;

i++;

ub1 = ((b & B_00001111) <4) + ((b2 & B_00111100) >>2);

ub2 = ((b2 & B_00000011) <6) + ((b3 & B_00111111));

charList.add(makeChar(ub1, ub2));

}else{

// 2 bytes

b2 = utf8Bytes[i+1];

if(!isNotHead(b2))continue;

i++;

ub1 = (b & B_00011100) >>2;

ub2 = ((b & B_00000011) <6) + (b2 & B_00111111);

charList.add(makeChar(ub1, ub2));

}

}

returncharList.toArray();

}

privatestaticbooleanisNotHead(byteb) {

return(b & B_11000000) == B_10000000;

}

privatestaticcharmakeChar(intb1,intb2) {

return(char) ((b1 <8) + b2);

}

publicstaticbyte[] fromUCS2(char[] ucs2Array) {

ByteArrayOutputStream baos =newByteArrayOutputStream();

for(inti =0; i

charch = ucs2Array[i];

if(ch <=0x007F) {

baos.write(ch);

}elseif(ch <=0x07FF) {

intub1 = ch >>8;

intub2 = ch &0xFF;

intb1 = B_11000000 + (ub1 <2) +  (ub2 >>6);

intb2 = B_10000000 + (ub2 & B_00111111);

baos.write(b1);

baos.write(b2);

}else{

intub1 = ch >>8;

intub2 = ch &0xFF;

intb1 = B_11100000 + (ub1 >>4);

intb2 = B_10000000 + ((ub1 & B_00001111) <2) + (ub2 >>6);

intb3 = B_10000000 + (ub2 & B_00111111);

baos.write(b1);

baos.write(b2);

baos.write(b3);

}

}

returnbaos.toByteArray();

}

privatestaticclassCharList {

privatechar[] data =null;

privateintused =0;

publicvoidadd(charc) {

if(data ==null) {

data =newchar[16];

}elseif(used >= data.length) {

char[] temp =newchar[data.length *2];

System.arraycopy(data,0, temp,0, used);

data = temp;

}

data[used++] = c;

}

publicchar[] toArray() {

char[] chars =newchar[used];

System.arraycopy(data,0, chars,0, used);

returnchars;

}

}

privatestaticvoidassert1(String s)throwsUnsupportedEncodingException {

byte[] b = s.getBytes("utf-8");

char[] c = toUCS2(b);

if(!s.equals(newString(c))) {

thrownewRuntimeException("Can not pass assert1 for: "+ s);

}

}

privatestaticvoidassert2(String s)throwsUnsupportedEncodingException {

byte[] b = s.getBytes("utf-8");

byte[] b2 = fromUCS2(s.toCharArray());

if(b.length == b2.length) {

inti;

for(i =0; i

if(b[i] != b2[i]) {

break;

}

}

if(i == b.length) {

return;

}

}

thrownewRuntimeException("Can not pass assert2 for: "+ s);

}

publicstaticvoidmain(String[] args)throwsException {

assert1("test");

assert1("中文测试");

assert1("A中V文c测d试E");

assert1("\u052CA\u052CBc测");

assert2("test");

assert2("中文测试");

assert2("A中V文c测d试E");

assert2("\u052CA\u052CBc测\u007F\u07FF");

System.out.println("pass");

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值