UNICODE与UTF-8的转换详解
UNICODE与UTF-8的转换详解
* 字符:字符是抽象的最小文本单位。它没有固定的形状(可能是一个字形),而且没有值。“A”是一个字符,“€”(德国、法国和许多其他欧洲国家通用货币的标志)也是一个字符。
* 字符集:字符集是字符的集合。例如,汉字字符是中国人最先发明的字符,在中文、日文、韩文和越南文的书写中使用。
* 编码字符集:编码字符集是一个字符集,它为每一个字符分配一个唯一数字。Unicode 标准的核心是一个编码字符集,字母“A”的编码为 004116 和字符“€”的编码为 20AC16。Unicode 标准始终使用十六进制数字,而且在书写时在前面加上前缀“U+”,所以“A”的编码书写为“U+0041”。
* 代码点:代码点是指可用于编码字符集的数字。编码字符集定义一个有效的代码点范围,但是并不一定将字符分配给所有这些代码点。有效的Unicode代码点范围是 U+0000 至U+10FFFF。Unicode4.0将字符分配给一百多万个代码点中的96,382代码点。
* 增补字符:增补字符是代码点在 U+10000 至 U+10FFFF 范围之间的字符,也就是那些使用原始的Unicode的16 位设计无法表示的字符。从U+0000至 U+FFFF之间的字符集有时候被称为基本多语言面 (BMP)。因此,每一个Unicode 字符要么属于BMP,要么属于增补字符。
* 字符编码方案:字符编码方案是从一个或多个编码字符集到一个或多个固定宽度代码单元序列的映射。最常用的代码单元是字节,但是 16 位或 32 位整数也可用于内部处理。UTF-32、UTF-16 和 UTF-8 是 Unicode 标准的编码字符集的字符编码方案。
* UTF-32:即将每一个 Unicode 代码点表示为相同值的 32 位整数。很明显,它是内部处理最方便的表达方式,但是,如果作为一般字符串表达方式,则要消耗更多的内存。
* UTF-16:使用一个或两个未分配的 16 位代码单元的序列对Unicode代码点进行编码。值U+0000至U+FFFF编码为一个相同值的16位单元。增补字符编码为两个代码单元,第一个单元来自于高代理范围(U+D800 至 U+DBFF),第二个单元来自于低代理范围(U+DC00至U+DFFF)。这在概念上可能看起来类似于多字节编码,但是其中有一个重要区别:值U+D800至U+DFFF 保留用于UTF-16;没有这些值分配字符作为代码点。这意味着,对于一个字符串中的每个单独的代码单元,软件可以识别是否该代码单元表示某个单单元字符,或者是否该代码单元是某个双单元字符的第一个或第二单元。这相当于某些传统的多字节字符编码来说是一个显著的改进,在传统的多字节字符编码中,字节值0x41既可能表示字母“A”,也可能是一个双字节字符的第二个字节。
* UTF-8:使用一至四个字节的序列对编码Unicode代码点进行编码。U+0000至U+007F 使用一个字节编码,U+0080至U+07FF使用两个字节,U+0800至U+FFFF 使用三个字节,而U+10000至U+10FFFF使用四个字节。UTF-8设计原理为:字节值0x00至0x7F 始终表示代码点U+0000至U+007F(Basic Latin 字符子集,它对应 ASCII 字符集)。这些字节值永远不会表示其他代码点,这一特性使UTF-8可以很方便地在软件中将特殊的含义赋予某些ASCII字符。
|
* 按汉字的排列顺序形成的编码(流水码):如区位码;
* 按汉字的读音形成的编码(音码):如全拼、简拼、双拼等;
* 按汉字的字形形成的编码(形码):如五笔字型、郑码等;
* 按汉字的音、形结合形成的编码(音形码):如自然码、智能ABC。
* 输入码在计算机中必须转换成机内码,才能进行存储和处理。
|
1:已知汉字"春"的国标码为343AH,求其机内码?
答:机内码 = 国标码 + 8080H = 343AH + 8080H = B4BAH
2:用24×24点阵来表示一个汉字(一点为一个二进制位),则2000个汉字需要多少KB容量?
答: 容量 = (24 * 24/8)* 2000 / 1024 = 140.7KB ≈ 141KB
|
Unicode 1.0:1991年10月;
Unicode 1.0.1:1992年6月;
Unicode 1.1:1993年6月;
Unicode 2.0:1997年7月;
Unicode 2.1:1998年5月;
Unicode 2.1.2:1998年5月;
Unicode 3.0:1999年9月;涵盖了来自ISO 10646-1的十六位元通用字符集(UCS)基本多文种平面(Basic Multilingual Plane);
Unicode 3.1:2001年3月;新增从ISO 10646-2定义的辅助平面(Supplementary Planes);
Unicode 3.2:2002年3月;
Unicode 4.0:2003年4月;
Unicode 4.0.1:2004年3月;
Unicode 4.1:2005年3月;
Unicode 5.0:2006年7月;
Unicode 5.1:2008年4月。
|
?单字节字符的最高有效位元永远为0;
?多字节序列中的首个字符组的几个最高有效位元决定了序列的长度。最高有效位为110的,是2字节序列,而1110的是三字节序列,如此类推;
?多字节序列中其余的字节中的首两个最高有效位元为10。
|
UCS-4(UNICODE)编码 | UTF-8字节流 |
U-00000000 – U-0000007F | 0xxxxxxx |
U-00000080 – U-000007FF | 110xxxxx 10xxxxxx |
U-00000800 – U-0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
U-00010000 – U-001FFFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
U-00200000 – U-03FFFFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
U-04000000 – U-7FFFFFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
![](http://writeblog.csdn.net/uploadfiles/Image/liujie/image_20090331131123.bmp)
![](http://writeblog.csdn.net/uploadfiles/Image/image_20090331131209.bmp)
![](http://writeblog.csdn.net/uploadfiles/Image/image_20090331131239.bmp)
/**
* 将utf-8编码转化为unicode编码
* @param aByte byte[] -原utf-8编码字节数组
* return sByte byte[] -转化后的unicode编码字节数组
*/
public static String changeUtf8ToUnicode(byte[] aByte) {
int sLength = aByte.length; //原字节数组长度
//存储转化为unicode编码后的StringBuffer字符串
StringBuffer sUnicodeStringBuffer = new StringBuffer();
char sChar; //用于临时存放每个从utf-8中解析出来的unicode编码
//以下操作是判断字节是否以"1110 xxxx 10xxxxxx 10xxxxxx"的形式出现
for (int i = 0; i < sLength; i++) { //循环每一个字节
if (i + 2 < sLength) {
/**
* aByte[i] & 0xF0 == 0xE0 ---> 判断当前字节是否以“1110”的形式开始;
* aByte[i + 1] & 0xC0 == 0x80 ---> 判断下一个字节是否以“10”的形式开始;
* aByte[i + 2] & 0xC0 == 0x80 ---> 判断下下一个字节是否以“10”的形式开始。
* 假如条件都满足,则表示此断字节进行了utf-8编码,则将对其进行解码操作(即转
* 化为unicode编码)
*/
if ((aByte[i] & 0xF0) == 0xE0 && (aByte[i + 1] & 0xC0) == 0x80 &&
(aByte[i + 2] & 0xC0) == 0x80) {
/**
* 将当前字节 1110 xxxx 转化为 xxxx 000000 000000 的形式,具体步骤为:
* 1110 xxxx << 12 = xxxx 000000 000000
* 1110 0100 << 12 = 0100 000000 000000
*/
sChar = (char) (aByte[i] << 12);
/**
* 将 前两个字节 转化为 xxxx xxxxxx 000000 的形式,具体步骤为:
* 10 xxxxxx & 0x003F = 0000 000000 xxxxxx
* 10 111000 & 0x003F = 0000 000000 111000
*
* 0000 000000 xxxxxx << 6 = 0000 xxxxxx 000000
* 0000 000000 111000 << 6 = 0000 111000 000000
*
* xxxx 000000 000000 | 0000 xxxxxx 000000 = xxxx xxxxxx 000000
* 0100 000000 000000 | 0000 111000 000000 = 0100 111000 000000
*/
sChar = (char) ((((aByte[i + 1] & 0x003F) << 6) | sChar));
/**
* 将此三个字节转化为 xxxx xxxxxx xxxxxx 的形式,具体步骤为:
* 10 xxxxxx & 0x003F = 0000 0000 00 xxxxxx
* 10 101101 & 0x003F = 0000 0000 00 101101
*
* xxxx xxxxxx 000000 | 0000 000000 xxxxxx = xxxx xxxxxx xxxxxx
* 0100 111000 000000 | 0000 000000 101101 = 0100 111000 101101
*/
sChar = (char) ((aByte[i + 2] & 0x003F) | sChar);
i = i + 2;
sUnicodeStringBuffer.append(sChar);
} else {
sUnicodeStringBuffer.append((char) aByte[i]);
}
}
}
return sUnicodeStringBuffer.toString();
}
|
/**
* 将UTF-8编码解码
* @param aByte byte[]
* @return String
*/
public static String changeUtf8ToUnicode(byte[] aByte) {
StringBuffer sUnicodeStringBuffer = new StringBuffer();
int sLength = aByte.length;
int sInt_1, sInt_2, sInt_3, sInt_4, sInt_5, sInt_6;
for (int i = 0; i < sLength; i++) {
sInt_1 = (int) aByte[i] & 0xff;
switch (sInt_1 >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
/* 0xxxxxxx*/
sUnicodeStringBuffer.append((char) aByte[i]);
break;
case 12:
case 13:
/* 110x xxxx 10xx xxxx*/
if (i + 1 < sLength) {
sInt_2 = (char) aByte[i + 1];
if ((sInt_2 & 0xC0) == 0x80) {
sUnicodeStringBuffer.append((char)(((sInt_1 & 0x1F) << 6)
| (sInt_2 & 0x3F)));
i ++;
}
}
break;
case 14:
/* 1110 xxxx 10xx xxxx 10xx xxxx */
if (i + 2 < sLength) {
sInt_2 = (int) aByte[i + 1];
sInt_3 = (int) aByte[i + 2];
if (((sInt_2 & 0xC0) == 0x80) || ((sInt_3 & 0xC0) == 0x80)) {
sUnicodeStringBuffer.append((char)(((sInt_1 & 0x0F) << 12) | ((sInt_2 & 0x3F) << 6) | ((sInt_3 & 0x3F) << 0)));
i = i + 2;
}
}
break;
}
}
return sUnicodeStringBuffer.toString();
}
|
* 重新定义基本类型char,使其具有32位,这样也会使所有形式的 char序列成为UTF-32序列;
* 在现有的16位类型char的基础上,为字符引入一种新的32位基本类型(例如,char32)。所有形式的Char序列均基于 UTF-16;
* 在现有的16位类型char的基础上,为字符引入一种新的32位基本类型(例如,char32)。String和StringBuffer 接受并行API,并将它们解释为UTF-16序列或UTF-32序列;其他char序列继续基于UTF-16;
* 使用int表示增补的代码点。String和StringBuffer接受并行API,并将它们解释为UTF-16序列或UTF-32序列;其他char序列继续基于UTF-16;
* 使用代理char对,表示增补代码点。所有形式的char序列基于UTF-16;
* 引入一种封装字符的类。String和StringBuffer接受新的API,并将它们解释为此类字符的序列;
* 使用一个CharSequence实例和一个索引的组合表示代码点。
|
* 使用基本类型int在低层API中表示代码点,例如Character类的静态方法。
* 将所有形式的char序列均解释为UTF-16序列,并促进其在更高层级API中的使用。
* 提供API,以方便在各种char和基于代码点的表示法之间的转换。
|
* Character.isLetter(int codePoint)可根据Unicode标准识别字母;
* Character.isJavaIdentifierStart(int codePoint)可根据Java语言规范确定代码点是否可以启动标识符;
* Character.UnicodeBlock.of(int codePoint)可搜索代码点所属的Unicode字符子集;
* Character.toUpperCase(int codePoint)可将给定的代码点转换为其大写等值字符。尽管此方法能够支持增补字符,但是它仍然不能解决根本的问题,即在某些情况下,逐个字符的转换无法正确完成。例如,德文字符“ß”应该转换为“SS”,这需要使用String.toUpperCase方法;
|
/**
* 创建仅含有指定代码点的新 String。
*/
String newString(int codePoint) {
return new String(Character.toChars(codePoint));
}
|
/**
* 创建仅含有指定代码点的新String。
* 针对BMP字符优化的版本。
*/
String newString(int codePoint) {
if (Character.charCount(codePoint) == 1) {
return String.valueOf((char) codePoint);
} else {
return new String(Character.toChars(codePoint));
}
}
|
/**
* 创建每一个均含有一个指定
* 代码点的新 String。
* 针对 BMP 字符优化的版本。
*/
String[] newStrings(int[] codePoints) {
String[] result = new String[codePoints.length];
char[] codeUnits = new char[2];
for (int i = 0; i < codePoints.length; i++) {
int count = Character.toChars(codePoints[i], codeUnits, 0);
result[i] = new String(codeUnits, 0, count);
}
return result;
}
|
System.out.println("Character " + String.valueOf(char) + " is invalid."); |
System.out.printf("Character %c is invalid.%n", codePoint); |
UNICODE与UTF-8的转换详解相关推荐
- [字符集]Unicode和UTF-8之间的转换详解
最近在用VC++开发一个小工具,平时用惯了.NET,用起VC++最郁闷的就是字符串处理.当然最最让人难于琢磨的就是字符集,编码之间的转换.通过这几天的研究,终于明白了Unicode和UTF-8 ...
- Unicode和UTF-8之间的转换详解
Unicode是一个字符集,而UTF-8是 Unicode的其中一种,Unicode是定长的都为双字节,而UTF-8是可变的,对于汉字来说Unicode占有的字节比UTF-8占用的字节少1 个字节.U ...
- UNICODE与 UTF8的转换详解
转载请注明出处: http://www.ins1000.cn/KnowledgeActionForReader?action=read&id=104 源文件下载地址:UTF- 8的转换详解(W ...
- UNICODE与 UTF-8 的转换详解
UNICODE与 UTF-8的转换详解 unicode 只是一种编码方式,而utf-8是unicode的一种保存或传输方式. 1 编码 在计算机中,各种信息都是以二进制编码的形式存在的,也就是说,不 ...
- PHP中IP地址与整型数字互相转换详解
这篇文章主要介绍了PHP中IP地址与整型数字互相转换详解,本文介绍了使用PHP函数ip2long与long2ip的使用,以及它们的BUG介绍,最后给出自己写的两个算法,需要的朋友可以参考下 IP转换成 ...
- VC常用数据类型使用转换详解
VC常用数据类型使用转换详解 出 处:PCVC.NET 作 者:程佩君 刚接触VC编程的朋友往往对许多数据类型的转换感到迷惑不解,本文将介绍一些常用数据类型的使用. 我们先定义一些常见类型变量借以 ...
- python datetime to timestamp_python timestamp和datetime之间转换详解
做开发中难免时间类型之间的转换, 最近就发现前端js和后端django经常要用到这个转换, 其中jsDate.now()精确到毫秒,而Python中Datetime.datetime.now()是精确 ...
- 直角坐标和求坐标的转换详解-关于球坐标转换为直角坐标正负号相反问题
最近项目用到直角坐标转换到球坐标,处理后再转回直角坐标作为最后的结果输出,结果发现转回去的直接坐标有的符号是相反的,找到原因记录如下. 1.直角坐标和求坐标的转换详解 其中关于角度反正切的计算可直接用 ...
- C语言标准库里的获取时间函数及时间格式转换详解
C语言标准库里的获取时间函数及时间格式转换详解 头文件: #include <time.h> 相关库函数(截图摘自:https://www.runoob.com/cprogramming/ ...
最新文章
- PHP开发移动端接口
- spire.doc 转html,c# html 转Word--Spire.Doc
- 网站推广专员浅析网站推广中网站优化的价值取向究竟为何?
- 浅谈DCIM平台的6化
- hdu 1269(Tarjan求强连通分量)
- android10 内部存储,Android的内部存储和外部存储
- SQL Server 语句查询手册
- wnoise matlab,MATLAB中用wnoise函数测试去噪算法
- JavaScript语言基础(二)
- SpringBoot 工程目录 整合mybatis-mysql(注解类型)
- Grad-CAM 神经网络特征图可视化
- 27. 用户生成内容
- spring aop切面执行顺序
- matlab数据类型 —— 整型
- Guava---Joiner
- maven 为html赋版本号,maven-replacer-plugin 静态资源版本号解决方案(css/js等)
- 7-1 图的先深搜索+7-2 图的先广搜索
- 关于shell unix下,直接执行shell与sh 执行 或加 . 脚本 的区别及含义
- ArcGIS教程:解决在mxd文件,定义投影之后,数据源还是的投影坐标系还是未发生改变的问题。
- pandas 之 pivot_table 与 pivot 的区别
热门文章
- 【python进阶】古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
- 天翼云服务器硬盘怎么挂载,用s3fs挂载天翼OOS到服务器
- 尤雨溪:VUE 3 之后会休息一下
- Python爬虫 | 图书馆公众号座位自动预约【从0到1】
- 日常生活收缩毛孔几个小妙招 - 生活至上,美容至尚!
- 手机屏幕常见故障_触屏不灵敏、断触怎么回事?手机触摸屏的基本原理与常见问题排查方法介绍...
- MATHLAB有关知识
- 2022年第十三届蓝桥杯大赛软件类国赛 C/C++ 大学B组
- Unity SpriteAtlas实战使用
- html 中箭头的代码,HTML中利用div+CSS实现简单的箭头图标的代码