当前位置:   article > 正文

严格的C风格字符串 Unicode To UTF-8 的实现(C#、JavaScript)_c#unicodestringtoutf8array

c#unicodestringtoutf8array

  本文是关于  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” 字符集相关的内容。

  1. public static byte[] GetUTF8StringBuffer(string s, out int count)
  2. {
  3. count = 0;
  4. if (s == null)
  5. {
  6. throw new ArgumentNullException("s");
  7. }
  8. byte[] buf = null;
  9. int k = 0;
  10. int i = 0;
  11. while (i < s.Length)
  12. {
  13. char ch = s[i++];
  14. if (ch < 0x80)
  15. {
  16. k++;
  17. }
  18. else if (ch < 0x800)
  19. {
  20. k += 2;
  21. }
  22. else if (ch < 0x10000)
  23. {
  24. k += 3;
  25. }
  26. }
  27. buf = new byte[(count = k) + 1];
  28. fixed (byte* p = buf)
  29. {
  30. i = 0;
  31. k = 0;
  32. while (i < s.Length)
  33. {
  34. char ch = s[i++];
  35. if (ch < 0x80)
  36. {
  37. p[k++] = (byte)(ch & 0xff);
  38. }
  39. else if (ch < 0x800)
  40. {
  41. p[k++] = (byte)(((ch >> 6) & 0x1f) | 0xc0);
  42. p[k++] = (byte)((ch & 0x3f) | 0x80);
  43. }
  44. else if (ch < 0x10000)
  45. {
  46. p[k++] = (byte)(((ch >> 12) & 0x0f) | 0xe0);
  47. p[k++] = (byte)(((ch >> 6) & 0x3f) | 0x80);
  48. p[k++] = (byte)((ch & 0x3f) | 0x80);
  49. }
  50. }
  51. }
  52. return buf;
  53. }

  第一个计次循环用于确定转换到UTF-8字符串,所需的字符串缓冲区大小(这是必须的)否则可以采取空间换效率的方式,一个wchar_t 的 Unicode 字符转换成 UTF-8 最大只占三个字节(所以随便浪),但是一个严格的C风格字符串必须携带 “\x0” 所以这就是为什么上面需要在测量的长度上加上 1 的问题,另外根据 “编码规则表” 上定义的说法,<= 0x7F 的字符也就是ASCII字符 都只占用一个字节而不是与 Unicode 一般,不论是不是ASCII字符都需要用双字节进行表示。

  1. var GetUtf8StringBuffer = function (s) {
  2. 'use strict'
  3. var buf = [];
  4. var k = 0;
  5. if (!s || typeof s !== 'string') {
  6. return buf;
  7. }
  8. for (var i = 0; i < s.length; i++) {
  9. var ch = s.charCodeAt(i);
  10. if (isNaN(ch)) {
  11. continue;
  12. }
  13. if (ch < 0x80) {
  14. k++;
  15. }
  16. else if (ch < 0x800) {
  17. k += 2;
  18. }
  19. else if (ch < 0x10000) {
  20. k += 3;
  21. }
  22. }
  23. buf = new Array(k + 1);
  24. buf[k] = 0;
  25. k = 0;
  26. for (var i = 0; i < s.length; i++) {
  27. var ch = s.charCodeAt(i);
  28. if (isNaN(ch)) {
  29. continue;
  30. }
  31. if (ch < 0x80) {
  32. buf[k++] = (ch & 0xff);
  33. }
  34. else if (ch < 0x800) {
  35. buf[k++] = ((ch >> 6) & 0x1f) | 0xc0;
  36. buf[k++] = (ch & 0x3f) | 0x80;
  37. }
  38. else if (ch < 0x10000) {
  39. buf[k++] = ((ch >> 12) & 0x0f) | 0xe0;
  40. buf[k++] = ((ch >> 6) & 0x3f) | 0x80;
  41. buf[k++] = (ch & 0x3f) | 0x80;
  42. }
  43. }
  44. return buf;
  45. }

    以下是 JavaScript 语言对于 “utf8” 字符集数组缓冲区转换成 “JavaScript” 的 Local<String> 的实现,(PS:JavaScript 语言默认并不支持UTF8的转换)

  1. var GetStringFromUtf8Buffer = function (utf8) {
  2. 'use strict'
  3. var s = '';
  4. if (!utf8 || !(utf8 instanceof Array) || utf8.length <= 0) {
  5. return s;
  6. }
  7. for (var k = 0; k < utf8.length;) {
  8. var ch = utf8[k++];
  9. if (ch < 0xE0) {
  10. ch = (ch & 0x1f) << 6;
  11. ch |= (utf8[k++] & 0x3f);
  12. } else if (ch < 0xF0) {
  13. ch = (ch & 0x0f) << 12;
  14. ch |= (utf8[k++] & 0x3f) << 6;
  15. ch |= (utf8[k++] & 0x3f);
  16. }
  17. if (ch > 0) {
  18. s += String.fromCharCode(ch);
  19. } else {
  20. break;
  21. }
  22. }
  23. return s;
  24. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/253359
推荐阅读
相关标签
  

闽ICP备14008679号