关于 unicode utf8

文章来自于 http://blog.csdn.net/tge7618291/article/details/7599902

ascii

主要来表示英文.但是要全世界那么多语言符号文字,ascii就不够使用了,为了统一,unicode出现了.

unicode

包含全世界所有的语言文字的编码方案.对于每个字符都有一个规定的二进制代码.

需要注意的是, "Unicode只是一个符号集, 它只规定了符号的二进制代码, 却没有规定这

个二进制代码应该如何存储".

unicode的问题

  1. 如何区分unicode和ascii编码?
  2. 如果unicode统一规定, 每个符号用三个或四个字节表示, 那么每个英文字母前都必然有二到三个字节是0, 这对于存来说是极大的浪费,文本文件的大小会因此大出二三倍, 这是无法接受的.

它们造成的结果是:

  1. 出现了unicode的多种存储方式, 也就是说有许多种不同的二进制格式,

    可以用来表示unicode.
  2. unicode在很长一段时间内无法推广, 直到互联网的出现

utf-8

互联网的普及, 强烈要求出现一种统一的编码方式. UTF-8就是在互联网上使用最广的一

种unicode的实现方式. 其他实现方式还包括UTF-16和UTF-32, 不过在互联网上基本不用.

重复一遍, 这里的关系是, UTF-8是Unicode的实现方式之一.

UTF-8最大的一个特点, 就是它是一种变长的编码方式. 它可以使用1~6个字节表示一个符

号, 根据不同的符号而变化字节长度.

utf-8的编码规则

  1. 对于单字节的符号, 字节的第一位设为0, 后面7位为这个符号的unicode码. 因此对于

    英语字母, UTF-8编码和ASCII码是相同的.

  2. 对于n字节的符号(n>1), 第一个字节的前n位都设为1, 第n+1位设为0, 后面字节的前

    两位一律设为10. 剩下的没有提及的二进制位, 全部为这个符号的unicode码.

下表总结了编码规则, 字母x表示可用编码的位.

0 | Unicode符号范围 | UTF-8编码方式

n | (十六进制) | (二进制)

---+-----------------------+------------------------------------------------------

1 | 0000 0000 - 0000 007F | 0xxxxxxx

2 | 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx

3 | 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

4 | 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

5 | 0020 0000 - 03FF FFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

6 | 0400 0000 - 7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

下面, 以汉字"严"为例, 演示如何实现UTF-8编码.

已知"严"的unicode是4E25(1001110 00100101), 根据上表, 可以发现4E25处在第三行的

范围内(0000 0800 - 0000 FFFF), 因此"严"的UTF-8编码需要三个字节, 即格式是

"1110xxxx 10xxxxxx 10xxxxxx". 然后, 从"严"的最后一个二进制位开始, 依次从后向前

填入格式中的x, 多出的位补0. 这样就得到了, "严"的UTF-8编码是 "11100100 10111000

10100101", 转换成十六进制就是E4B8A5.

Little endian和Big endian

上一节已经提到, Unicode码可以采用UCS-2格式直接存储. 以汉字"严"为例, Unicode码

是4E25, 需要用两个字节存储, 一个字节是4E, 另一个字节是25. 存储的时候, 4E在前,

25在后, 就是Big endian方式; 25在前, 4E在后, 就是Little endian方式.

// Big Endian(4E25) Little Endian(254E)

因此, 第一个字节在前, 就是"大头方式"(Big endian), 第二个字节在前就是"小头方式

"(Little endian).

计算机怎么知道某一个文件到底采用哪一种方式编码?(零宽度非换行空格(FEFF))

Unicode规范中定义, 每一个文件的最前面分别加入一个表示编码顺序的字符, 这个字符

的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE), 用FEFF表示. 这正好是

两个字节, 而且FF比FE大1.

// Big Endian(FEFF) Little Endian(FFFE)

NOTE:

如果一个文本文件的头两个字节是FE FF, 就表示该文件采用大头方式; 如果头两个字节

是FF FE, 就表示该文件采用小头方式.

utf8 和 unicode 之间的转换代码,

  1. // #c---
  2. /*****************************************************************************
  3. * 将一个字符的Unicode(UCS-2和UCS-4)编码转换成UTF-8编码.
  4. *
  5. * 参数:
  6. * unic 字符的Unicode编码值
  7. * pOutput 指向输出的用于存储UTF8编码值的缓冲区的指针
  8. * outsize pOutput缓冲的大小
  9. *
  10. * 返回值:
  11. * 返回转换后的字符的UTF8编码所占的字节数, 如果出错则返回 0 .
  12. *
  13. * 注意:
  14. * 1. UTF8没有字节序问题, 但是Unicode有字节序要求;
  15. * 字节序分为大端(Big Endian)和小端(Little Endian)两种;
  16. * 在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位)
  17. * 2. 请保证 pOutput 缓冲区有最少有 6 字节的空间大小!
  18. ****************************************************************************/
  19. int enc_unicode_to_utf8_one(unsigned long unic, unsigned char *pOutput,
  20. int outSize){
  21. assert(pOutput != NULL);
  22. assert(outSize >= 6);
  23. if ( unic <= 0x0000007F )
  24. {
  25. // * U-00000000 - U-0000007F: 0xxxxxxx
  26. *pOutput = (unic & 0x7F);
  27. return 1;
  28. }
  29. else if ( unic >= 0x00000080 && unic <= 0x000007FF )
  30. {
  31. // * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
  32. *(pOutput+1) = (unic & 0x3F) | 0x80;
  33. *pOutput = ((unic >> 6) & 0x1F) | 0xC0;
  34. return 2;
  35. }
  36. else if ( unic >= 0x00000800 && unic <= 0x0000FFFF )
  37. {
  38. // * U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
  39. *(pOutput+2) = (unic & 0x3F) | 0x80;
  40. *(pOutput+1) = ((unic >> 6) & 0x3F) | 0x80;
  41. *pOutput = ((unic >> 12) & 0x0F) | 0xE0;
  42. return 3;
  43. }
  44. else if ( unic >= 0x00010000 && unic <= 0x001FFFFF )
  45. {
  46. // * U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  47. *(pOutput+3) = (unic & 0x3F) | 0x80;
  48. *(pOutput+2) = ((unic >> 6) & 0x3F) | 0x80;
  49. *(pOutput+1) = ((unic >> 12) & 0x3F) | 0x80;
  50. *pOutput = ((unic >> 18) & 0x07) | 0xF0;
  51. return 4;
  52. }
  53. else if ( unic >= 0x00200000 && unic <= 0x03FFFFFF )
  54. {
  55. // * U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  56. *(pOutput+4) = (unic & 0x3F) | 0x80;
  57. *(pOutput+3) = ((unic >> 6) & 0x3F) | 0x80;
  58. *(pOutput+2) = ((unic >> 12) & 0x3F) | 0x80;
  59. *(pOutput+1) = ((unic >> 18) & 0x3F) | 0x80;
  60. *pOutput = ((unic >> 24) & 0x03) | 0xF8;
  61. return 5;
  62. }
  63. else if ( unic >= 0x04000000 && unic <= 0x7FFFFFFF )
  64. {
  65. // * U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  66. *(pOutput+5) = (unic & 0x3F) | 0x80;
  67. *(pOutput+4) = ((unic >> 6) & 0x3F) | 0x80;
  68. *(pOutput+3) = ((unic >> 12) & 0x3F) | 0x80;
  69. *(pOutput+2) = ((unic >> 18) & 0x3F) | 0x80;
  70. *(pOutput+1) = ((unic >> 24) & 0x3F) | 0x80;
  71. *pOutput = ((unic >> 30) & 0x01) | 0xFC;
  72. return 6;
  73. }
  74. return 0;
  75. }
  76. // #c---end
  77. int enc_get_utf8_size(const unsigned char pInput){
  78. unsigned char c = pInput;
  79. // 0xxxxxxx 返回0
  80. // 10xxxxxx 不存在
  81. // 110xxxxx 返回2
  82. // 1110xxxx 返回3
  83. // 11110xxx 返回4
  84. // 111110xx 返回5
  85. // 1111110x 返回6
  86. if(c< 0x80) return 0;
  87. if(c>=0x80 && c<0xC0) return -1;
  88. if(c>=0xC0 && c<0xE0) return 2;
  89. if(c>=0xE0 && c<0xF0) return 3;
  90. if(c>=0xF0 && c<0xF8) return 4;
  91. if(c>=0xF8 && c<0xFC) return 5;
  92. if(c>=0xFC) return 6;
  93. return -1;
  94. }
  95. /*****************************************************************************
  96. * 将一个字符的UTF8编码转换成Unicode(UCS-2和UCS-4)编码.
  97. *
  98. * 参数:
  99. * pInput 指向输入缓冲区, 以UTF-8编码
  100. * Unic 指向输出缓冲区, 其保存的数据即是Unicode编码值,
  101. * 类型为unsigned long .
  102. *
  103. * 返回值:
  104. * 成功则返回该字符的UTF8编码所占用的字节数; 失败则返回0.
  105. *
  106. * 注意:
  107. * 1. UTF8没有字节序问题, 但是Unicode有字节序要求;
  108. * 字节序分为大端(Big Endian)和小端(Little Endian)两种;
  109. * 在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位)
  110. ****************************************************************************/
  111. int enc_utf8_to_unicode_one(const unsigned char* pInput, unsigned long *Unic)
  112. {
  113. assert(pInput != NULL && Unic != NULL);
  114. // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...
  115. char b1, b2, b3, b4, b5, b6;
  116. *Unic = 0x0; // 把 *Unic 初始化为全零
  117. int utfbytes = enc_get_utf8_size(*pInput);
  118. unsigned char *pOutput = (unsigned char *) Unic;
  119. switch ( utfbytes )
  120. {
  121. case 0:
  122. *pOutput = *pInput;
  123. utfbytes += 1;
  124. break;
  125. case 2:
  126. b1 = *pInput;
  127. b2 = *(pInput + 1);
  128. if ( (b2 & 0xE0) != 0x80 )
  129. return 0;
  130. *pOutput = (b1 << 6) + (b2 & 0x3F);
  131. *(pOutput+1) = (b1 >> 2) & 0x07;
  132. break;
  133. case 3:
  134. b1 = *pInput;
  135. b2 = *(pInput + 1);
  136. b3 = *(pInput + 2);
  137. if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) )
  138. return 0;
  139. *pOutput = (b2 << 6) + (b3 & 0x3F);
  140. *(pOutput+1) = (b1 << 4) + ((b2 >> 2) & 0x0F);
  141. break;
  142. case 4:
  143. b1 = *pInput;
  144. b2 = *(pInput + 1);
  145. b3 = *(pInput + 2);
  146. b4 = *(pInput + 3);
  147. if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
  148. || ((b4 & 0xC0) != 0x80) )
  149. return 0;
  150. *pOutput = (b3 << 6) + (b4 & 0x3F);
  151. *(pOutput+1) = (b2 << 4) + ((b3 >> 2) & 0x0F);
  152. *(pOutput+2) = ((b1 << 2) & 0x1C) + ((b2 >> 4) & 0x03);
  153. break;
  154. case 5:
  155. b1 = *pInput;
  156. b2 = *(pInput + 1);
  157. b3 = *(pInput + 2);
  158. b4 = *(pInput + 3);
  159. b5 = *(pInput + 4);
  160. if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
  161. || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80) )
  162. return 0;
  163. *pOutput = (b4 << 6) + (b5 & 0x3F);
  164. *(pOutput+1) = (b3 << 4) + ((b4 >> 2) & 0x0F);
  165. *(pOutput+2) = (b2 << 2) + ((b3 >> 4) & 0x03);
  166. *(pOutput+3) = (b1 << 6);
  167. break;
  168. case 6:
  169. b1 = *pInput;
  170. b2 = *(pInput + 1);
  171. b3 = *(pInput + 2);
  172. b4 = *(pInput + 3);
  173. b5 = *(pInput + 4);
  174. b6 = *(pInput + 5);
  175. if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)
  176. || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80)
  177. || ((b6 & 0xC0) != 0x80) )
  178. return 0;
  179. *pOutput = (b5 << 6) + (b6 & 0x3F);
  180. *(pOutput+1) = (b5 << 4) + ((b6 >> 2) & 0x0F);
  181. *(pOutput+2) = (b3 << 2) + ((b4 >> 4) & 0x03);
  182. *(pOutput+3) = ((b1 << 6) & 0x40) + (b2 & 0x3F);
  183. break;
  184. default:
  185. return 0;
  186. break;
  187. }
  188. return utfbytes;
  189. }
  190. // #c---end
  191. // for test
  192. int main(){
  193. const char* utf_text = "我"; // \u6211
  194. unsigned long unicode_text = 0;
  195. enc_utf8_to_unicode_one((unsigned char*)utf_text,&unicode_text);
  196. printf("unicode is : %lx\n",unicode_text);
  197. // 再将 unicode 转换成 utf8
  198. unsigned char utf_result[8] = {0};
  199. enc_unicode_to_utf8_one(unicode_text,utf_result,8);
  200. printf("utf8 is : %s\n",utf_result);
  201. return 0;
  202. }

unicode 和 utf8的更多相关文章

  1. Unicode 和 UTF-8 有何区别?

    Unicode符号范围 (一个字符两个字节)     | UTF-8编码方式 (十六进制)     | (二进制) —————————————————————– 这儿有四个字节从-----00 00 ...

  2. Unicode和UTF-8的关系

    Unicode和UTF-8都是表示编码,这个我一直都知道,但是这两个实际上是干什么用的,到底是怎么编码的,为什么有了Unicode还要UTF-8,它们之间有什么联系又有什么区别呢?这个问题一直困扰着我 ...

  3. 字符编码笔记:ASCII,Unicode和UTF-8

    很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到8个开关状态是好的,于是他们把这称为"字节". 再后来,他们又做了一些可以处理 ...

  4. 字符编码笔记:ASCII,Unicode和UTF-8 转

    本文出处 http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 只是为了记录一下省得要去搜. 今天中午,我突然想搞清楚 ...

  5. [转]字符编码笔记:ASCII,Unicode和UTF-8

    转自:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 作者: 阮一峰 日期: 2007年10月28日 今天中午, ...

  6. 字符编码笔记:ASCII,Unicode和UTF-8(转载)

    作者: 阮一峰 日期: 2007年10月28日 今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料. 结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步 ...

  7. 简单几句话总结Unicode,UTF-8和UTF-16

    概念 先说一说基本的概念,这包括什么是Unicode,什么是UTF-8,什么是UTF-16. Unicode,UTF-8,UTF-16完整的说明请参考Wiki(Unicode,UTF-8,UTF-16 ...

  8. Unicode 和 UTF-8 的关系

    曾经这个世界上,有着gb2312,gbk,latin1,utf 等各种字符集,现在,我们也能不时的看到他们的身影. 但是值得庆幸的事,时过境迁,这些主要的字符集,都已经逐渐被utf8取代. 但是我们很 ...

  9. unicode,ansi,utf-8,unicode big endian编码的区别

    知乎--http://www.zhihu.com/question/23374078 http://wenku.baidu.com/view/cb9fe505cc17552707220865.html ...

  10. 关于几种编码详解(Unicode,UTF-8,GB系列)

    最近学Python,老是被编码的问题搞得晕乎乎的,晚上看了好多篇博客,整理出来一个比较清晰的关于几种编码以及字符集的思路. 主要参考:http://blog.sina.com.cn/s/blog_6d ...

随机推荐

  1. 【转载】跟随 Web 标准探究DOM -- Node 与 Element 的遍历

    跟随 Web 标准探究DOM -- Node 与 Element 的遍历 这个是 Joyee 2014年更新的,可能是转战github缘故,一年多没有跟新了.这篇感觉还挺全面,就转载过来,如以前文章一 ...

  2. php-fpm优化方法详解

    php-fpm优化方法 php-fpm存在两种方式,一种是直接开启指定数量的php-fpm进程,不再增加或者减少:另一种则是开始时开启一定数量的php-fpm进程,当请求量变大时,动态的增加php-f ...

  3. Why did I have a recovery trip

    For more than a decade, I felt most at ease living out of a suitcase, never quite sure where I might ...

  4. Excel——使用OFFSET、MATCH、COUNTA实现二级菜单

    如图所示,接下来提供两种办法实现: 1.将A.B.C.D定义为名称NAME. 2.设置一级菜单单元格数据有效性为NAME. 3.设置二级菜单格数据有效为: =OFFSET($A$1,MATCH($A6 ...

  5. [Evolutionary Algorithm] 进化算法简介

    进化算法,也被成为是演化算法(evolutionary algorithms,简称EAs),它不是一个具体的算法,而是一个“算法簇”.进化算法的产生的灵感借鉴了大自然中生物的进化操作,它一般包括基因编 ...

  6. Python 局部变量与全局变量

    本来以为 局部变量就是在函数/def/class/lambda内部的变量,全局变量就是在之前这些之外的变量.但是,再一次学习Python atm 中应用时发现了一次特例(意外) 字典中 在函数内部改变 ...

  7. 第4月第1天 makefile automake

    1. gnu make的函数调用是$,比如 $(subst ee,EE,feet on the street) 规则中“TARGETS”可以是空格分开的多个文件名 a all: echo $(subs ...

  8. 第3月第16天 fd_set 32 ACE_TP_Reactor

    1. #ifdef FD_SETSIZE #define __DARWIN_FD_SETSIZE FD_SETSIZE #else /* !FD_SETSIZE */ #define __DARWIN ...

  9. 读取图像,LUT以及计算耗时

    使用LUT(lookup table)检索表的方法,提高color reduce时对像素读取的速度. 实现对Mat对象中数据的读取,并计算color reduce的速度. 方法一:使用Mat的ptr( ...

  10. js array push 添加内容

    向数组中天机内容: var array = new Array(); array.push('newItem');