赞
踩
本文是关于 Unicode 也就是 LPWSTR 转换成 UTF-8 的实现,在 Win32k 平台中我们可以借助 “MultiByteToWideChar / WideCharToMultiByte”【核心编程】两个函数进行多字节与宽字节字符串进行转换【PS:A2W / W2A 无法转换,CP_ACP在WIN32中文版上为936(GBK简体中文)】
.NET Framework 提供 “System.Text.Encoding.UTF8” 可以进行 .NET 字符串与 UTF8 字符串之间的转换,例:C# 语言执行字符集是 Unicode,并且这是强制性的不存在可以无法更改 “执行字符集” 的说法。
现代的 C/CXX 语言,都可以利用 “#pragma execution_character_set("utf-8")” 设定执行字符集,但这仅仅只是编译器层面的,而 “工程属性-字符集” 设定它仅仅是影响到几个编译器内部指定的约定宏。
Unicode/UCS-4 | bit数 | UTF-8 | byte数 | 备注 |
0000 ~ 007F | 0~7 | 0XXX XXXX | 1 | |
0080 ~ 07FF | 8~11 | 110X XXXX 10XX XXXX | 2 | |
0800 ~ FFFF | 12~16 | 1110XXXX 10XX XXXX 10XX XXXX | 3 | 基本定义范围:0~FFFF |
1 0000 ~ 1F FFFF | 17~21 | 1111 0XXX 10XX XXXX 10XX XXXX 10XX XXXX | 4 | Unicode6.1定义范围:0~10 FFFF |
20 0000 ~ 3FF FFFF | 22~26 | 1111 10XX 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX | 5 | 说明:此非unicode编码范围,属于UCS-4 编码 早期的规范UTF-8可以到达6字节序列,可以覆盖到31位元(通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中 |
400 0000 ~ 7FFF FFFF | 27~31 | 1111 110X 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX | 6 |
上表是UTF-8字符集编码定义的取值范围, 但事实情况 JavaScript、C# 语言的执行字符集都是 “Unicode” 编码 而不是UTF-8 或许会有人感到奇怪,但本人或许可以理解,一般来说 Unicode 的字符表示范围足够表示目前世界上已知的所有语言的字符,而UTF-8字符集中占用4、5、6字节的字符串你几乎很难遇到它们。
本文中 C# 的 Unicode To UTF-8 的代码,摘要自本人的 nsjsdotnet 框架,你可以从 “https://github.com/liulilittle/nsjs/blob/master/nsjsdotnet/NSJSString.cs” 中获取到更多与 “UTF8” 字符集相关的内容。
- public static byte[] GetUTF8StringBuffer(string s, out int count)
- {
- count = 0;
- if (s == null)
- {
- throw new ArgumentNullException("s");
- }
- byte[] buf = null;
- int k = 0;
- int i = 0;
- while (i < s.Length)
- {
- char ch = s[i++];
- if (ch < 0x80)
- {
- k++;
- }
- else if (ch < 0x800)
- {
- k += 2;
- }
- else if (ch < 0x10000)
- {
- k += 3;
- }
- }
- buf = new byte[(count = k) + 1];
- fixed (byte* p = buf)
- {
- i = 0;
- k = 0;
- while (i < s.Length)
- {
- char ch = s[i++];
- if (ch < 0x80)
- {
- p[k++] = (byte)(ch & 0xff);
- }
- else if (ch < 0x800)
- {
- p[k++] = (byte)(((ch >> 6) & 0x1f) | 0xc0);
- p[k++] = (byte)((ch & 0x3f) | 0x80);
- }
- else if (ch < 0x10000)
- {
- p[k++] = (byte)(((ch >> 12) & 0x0f) | 0xe0);
- p[k++] = (byte)(((ch >> 6) & 0x3f) | 0x80);
- p[k++] = (byte)((ch & 0x3f) | 0x80);
- }
- }
- }
- return buf;
- }
第一个计次循环用于确定转换到UTF-8字符串,所需的字符串缓冲区大小(这是必须的)否则可以采取空间换效率的方式,一个wchar_t 的 Unicode 字符转换成 UTF-8 最大只占三个字节(所以随便浪),但是一个严格的C风格字符串必须携带 “\x0” 所以这就是为什么上面需要在测量的长度上加上 1 的问题,另外根据 “编码规则表” 上定义的说法,<= 0x7F 的字符也就是ASCII字符 都只占用一个字节而不是与 Unicode 一般,不论是不是ASCII字符都需要用双字节进行表示。
- var GetUtf8StringBuffer = function (s) {
- 'use strict'
-
- var buf = [];
- var k = 0;
- if (!s || typeof s !== 'string') {
- return buf;
- }
- for (var i = 0; i < s.length; i++) {
- var ch = s.charCodeAt(i);
- if (isNaN(ch)) {
- continue;
- }
- if (ch < 0x80) {
- k++;
- }
- else if (ch < 0x800) {
- k += 2;
- }
- else if (ch < 0x10000) {
- k += 3;
- }
- }
- buf = new Array(k + 1);
- buf[k] = 0;
- k = 0;
- for (var i = 0; i < s.length; i++) {
- var ch = s.charCodeAt(i);
- if (isNaN(ch)) {
- continue;
- }
- if (ch < 0x80) {
- buf[k++] = (ch & 0xff);
- }
- else if (ch < 0x800) {
- buf[k++] = ((ch >> 6) & 0x1f) | 0xc0;
- buf[k++] = (ch & 0x3f) | 0x80;
- }
- else if (ch < 0x10000) {
- buf[k++] = ((ch >> 12) & 0x0f) | 0xe0;
- buf[k++] = ((ch >> 6) & 0x3f) | 0x80;
- buf[k++] = (ch & 0x3f) | 0x80;
- }
- }
- return buf;
- }
以下是 JavaScript 语言对于 “utf8” 字符集数组缓冲区转换成 “JavaScript” 的 Local<String> 的实现,(PS:JavaScript 语言默认并不支持UTF8的转换)
- var GetStringFromUtf8Buffer = function (utf8) {
- 'use strict'
-
- var s = '';
- if (!utf8 || !(utf8 instanceof Array) || utf8.length <= 0) {
- return s;
- }
- for (var k = 0; k < utf8.length;) {
- var ch = utf8[k++];
- if (ch < 0xE0) {
- ch = (ch & 0x1f) << 6;
- ch |= (utf8[k++] & 0x3f);
- } else if (ch < 0xF0) {
- ch = (ch & 0x0f) << 12;
- ch |= (utf8[k++] & 0x3f) << 6;
- ch |= (utf8[k++] & 0x3f);
- }
- if (ch > 0) {
- s += String.fromCharCode(ch);
- } else {
- break;
- }
- }
- return s;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。