- UID
- 1
- 精华
- 积分
- 76361
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
UTF-8编码的字符串,不同的字符长度不一样。和Unicode作为对比,Unicode的字符串每个字符的长度都是固定的,比如16位的Unicode(也就是Windows使用的这种)它就是2个字节一个字符(即便是半角字母)的固定长度字符数组。
UTF-8是一种针对Unicode的可变长度字元编码,也是一种前缀码。它可以用来表示Unicode标准中的任何字元。[参考]
在Unicode字符值小于128的时候,UTF-8可以只用一个字节来表示一个字符,这点可以做到和ASCII兼容。因此,这使得原来处理ASCII字元的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码。[参考]
使用UTF-8编码的字符串,其中的字符的长度取决于这个字符的值。我们可以用下面这张表很直观地将编码方式表示出来。
字符的位数范围 | 开始值 | 结束值 | UTF-8字节数 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | 0-7 | 0x00 | 0x7F | 1 | 0xxxxxxx | 8-11 | 0x80 | 0x7FF | 2 | 110xxxxx | 10xxxxxx | 12-16 | 0x800 | 0xFFFF | 3 | 1110xxxx | 10xxxxxx | 10xxxxxx | 17-21 | 0x10000 | 0x1FFFFF | 4 | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 22-26 | 0x200000 | 0x3FFFFFF | 5 | 111110xx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 27-31 | 0x4000000 | 0x7FFFFFFF | 6 | 1111110x | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
其中的“xxxxxx”就是原字符的二进制位了。UTF-8编码将Unicode字符值的高位放在靠前的字节,而低位则放在靠后的字节中。
知道了以上的信息之后,你大概也知道怎么写Unicode到UTF-8之间互转的函数了吧?
这里放出我写好的库,它不使用API,直接就能编码、解码UTF-8的字符串为Unicode了。- //=============================================================================
- //作者:0xAA55
- //作者网站:http://www.0xaa55.com/
- //本源码完全免费开放,大家可以随意拿去使用、修改、用于任何用途。
- //但是,由于本源码带来的任何损失,均与本作者无关。请保留此信息。
- //
- //参考资料:
- //RFC 3629
- //https://zh.wikipedia.org/wiki/UTF-8
- //http://www.0xaa55.com/thread-1676-1-1.html
- //-----------------------------------------------------------------------------
- #include"wcs2utf8.h"
- //=============================================================================
- //函数:_u16toutf8
- //描述:将16位Unicode编码的字符串转换为UTF-8
- // 返回转换为UTF-8后的字符串的长度。pUTF8可为NULL,表示不接收转换好的字符串
- //-----------------------------------------------------------------------------
- size_t _u16toutf8
- (
- char*pUTF8,
- const uint16_t*pwStr,
- size_t count
- )
- {
- size_t cbUTF8 = 0;
- size_t i;
- char*pChr;
- //pUTF8为NULL时,返回存储UTF-8字符串所需字节数
- if(!pUTF8)
- {
- for(i=0;i<count;i++)
- {
- if(pwStr[i] >= 0x0800)
- cbUTF8 += 3;
- else if(pwStr[i] >= 0x0080)
- cbUTF8 += 2;
- else
- cbUTF8++;
- }
- return cbUTF8;
- }
-
- //输出UTF-8编码的字符串
- pChr = pUTF8;
- for(i=0;i<count;i++)
- {
- if(pwStr[i] >= 0x0800)
- {
- *pChr++ = 0xE0 | ((pwStr[i] >> 12) & 0x0F);
- *pChr++ = 0x80 | ((pwStr[i] >> 6) & 0x3F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 3;
- }
- else if(pwStr[i] >= 0x0080)
- {
- *pChr++ = 0xC0 | ((pwStr[i] >> 6) & 0x1F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 2;
- }
- else
- {
- *pChr++ = (char)pwStr[i];
- cbUTF8++;
- }
- }
- return cbUTF8;
- }
- //=============================================================================
- //函数:_u32toutf8
- //描述:将32位Unicode编码的字符串转换为UTF-8
- // 返回转换为UTF-8后的字符串的长度。pUTF8可为NULL,表示不接收转换好的字符串
- //-----------------------------------------------------------------------------
- size_t _u32toutf8
- (
- char*pUTF8,
- const uint32_t*pwStr,
- size_t count
- )
- {
- size_t cbUTF8 = 0;
- size_t i;
- char*pChr;
- //pUTF8为NULL时,返回存储UTF-8字符串所需字节数
- if(!pUTF8)
- {
- for(i=0;i<count;i++)
- {
- if(pwStr[i] >= 0x4000000)
- cbUTF8 += 6;
- else if(pwStr[i] >= 0x200000)
- cbUTF8 += 5;
- else if(pwStr[i] >= 0x10000)
- cbUTF8 += 4;
- else if(pwStr[i] >= 0x0800)
- cbUTF8 += 3;
- else if(pwStr[i] >= 0x0080)
- cbUTF8 += 2;
- else
- cbUTF8++;
- }
- return cbUTF8;
- }
-
- //输出UTF-8编码的字符串
- pChr = pUTF8;
- for(i=0;i<count;i++)
- {
- if(pwStr[i] >= 0x4000000)
- {
- *pChr++ = 0xFC | ((pwStr[i] >> 30) & 0x01);
- *pChr++ = 0x80 | ((pwStr[i] >> 24) & 0x3F);
- *pChr++ = 0x80 | ((pwStr[i] >> 18) & 0x3F);
- *pChr++ = 0x80 | ((pwStr[i] >> 12) & 0x3F);
- *pChr++ = 0x80 | ((pwStr[i] >> 6) & 0x3F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 6;
- }
- else if(pwStr[i] >= 0x200000)
- {
- *pChr++ = 0xF8 | ((pwStr[i] >> 24) & 0x03);
- *pChr++ = 0x80 | ((pwStr[i] >> 18) & 0x3F);
- *pChr++ = 0x80 | ((pwStr[i] >> 12) & 0x3F);
- *pChr++ = 0x80 | ((pwStr[i] >> 6) & 0x3F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 5;
- }
- else if(pwStr[i] >= 0x10000)
- {
- *pChr++ = 0xF0 | ((pwStr[i] >> 18) & 0x07);
- *pChr++ = 0x80 | ((pwStr[i] >> 12) & 0x3F);
- *pChr++ = 0x80 | ((pwStr[i] >> 6) & 0x3F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 4;
- }
- else if(pwStr[i] >= 0x0800)
- {
- *pChr++ = 0xE0 | ((pwStr[i] >> 12) & 0x0F);
- *pChr++ = 0x80 | ((pwStr[i] >> 6) & 0x3F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 3;
- }
- else if(pwStr[i] >= 0x0080)
- {
- *pChr++ = 0xC0 | ((pwStr[i] >> 6) & 0x1F);
- *pChr++ = 0x80 | (pwStr[i] & 0x3F);
- cbUTF8 += 2;
- }
- else
- {
- *pChr++ = (char)pwStr[i];
- cbUTF8++;
- }
- }
- return cbUTF8;
- }
- //=============================================================================
- //函数:_GetUTF8NbWChars
- //描述:取得UTF-8字符串转换为Unicode编码的字符串的字符数
- // 失败返回0
- //-----------------------------------------------------------------------------
- static size_t _GetUTF8NbWChars(const char*pUTF8,size_t cb)
- {
- size_t cchUnicode = 0;
- size_t i;
- for(i=0;i<cb;)
- {
- if((pUTF8[i] & 0xFE) == 0xFC)
- {
- cchUnicode++;
- i += 6;
- }
- else if((pUTF8[i] & 0xFC) == 0xF8)
- {
- cchUnicode++;
- i += 5;
- }
- else if((pUTF8[i] & 0xF8) == 0xF0)
- {
- cchUnicode++;
- i += 4;
- }
- else if((pUTF8[i] & 0xF0) == 0xE0)
- {
- cchUnicode++;
- i += 3;
- }
- else if((pUTF8[i] & 0xE0) == 0xC0)
- {
- cchUnicode++;
- i += 2;
- }
- else if((pUTF8[i] & 0xC0) == 0x80)
- {
- //遇到高2位是10的字符,这是不应该出现的。
- return 0;
- }
- else if((pUTF8[i] & 0x80) == 0x00)
- {
- cchUnicode++;
- i++;
- }
- }
- //字符串不完整
- if(i > cb)
- cchUnicode--;
- return cchUnicode;
- }
- //=============================================================================
- //函数:_utf8tou16
- //描述:将UTF-8编码的字符串转换为16位Unicode
- // 返回转换为Unicode后的字符串的字符数。pUnicode可为NULL,表示不接收字符串。
- // 注意失败返回0
- //-----------------------------------------------------------------------------
- size_t _utf8tou16
- (
- uint16_t*pUnicode,
- const char*pUTF8,
- size_t cb
- )
- {
- size_t cchUnicode = 0;
- size_t i;
- uint16_t*pChr;
- if(!pUnicode)
- return _GetUTF8NbWChars(pUTF8,cb);
- pChr = pUnicode;
- for(i=0;i<cb;)
- {
- if( (pUTF8[i] & 0xFE) == 0xFC ||
- (pUTF8[i] & 0xFC) == 0xF8 ||
- (pUTF8[i] & 0xF8) == 0xF0)
- {
- //遇到32位Unicode字符,停止。本函数不包这服务。
- return 0;
- }
- else if((pUTF8[i] & 0xF0) == 0xE0)
- {
- if(i + 3 <= cb)
- {
- *pChr++ =
- (((uint16_t)pUTF8[i+0] & 0x0F) << 12)|
- (((uint16_t)pUTF8[i+1] & 0x3F) << 6)|
- (((uint16_t)pUTF8[i+2] & 0x3F) << 0);
- cchUnicode++;
- i += 3;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xE0) == 0xC0)
- {
- if(i + 2 <= cb)
- {
- *pChr++ =
- (((uint16_t)pUTF8[i+0] & 0x1F) << 6)|
- (((uint16_t)pUTF8[i+1] & 0x3F) << 0);
- cchUnicode++;
- i += 2;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xC0) == 0x80)
- {
- //遇到高2位是10的字符,这是不应该出现的。
- return 0;
- }
- else if((pUTF8[i] & 0x80) == 0x00)
- {
- *pChr++ = pUTF8[i] & 0x7F;
- cchUnicode++;
- i++;
- }
- }
- return cchUnicode;
- }
- //=============================================================================
- //函数:_utf8tou32
- //描述:将UTF-8编码的字符串转换为32位Unicode
- // 返回转换为Unicode后的字符串的字符数。pUnicode可为NULL,表示不接收字符串。
- // 注意失败返回0
- //-----------------------------------------------------------------------------
- size_t _utf8tou32
- (
- uint32_t*pUnicode,
- const char*pUTF8,
- size_t cb
- )
- {
- size_t cchUnicode = 0;
- size_t i;
- uint32_t*pChr;
- if(!pUnicode)
- return _GetUTF8NbWChars(pUTF8,cb);
- pChr = pUnicode;
- for(i=0;i<cb;)
- {
- if((pUTF8[i] & 0xFE) == 0xFC)//1111110x
- {
- if(i + 6 <= cb)
- {
- *pChr++ =
- (((uint32_t)pUTF8[i+0] & 0x01) << 30)|
- (((uint32_t)pUTF8[i+1] & 0x3F) << 24)|
- (((uint32_t)pUTF8[i+2] & 0x3F) << 18)|
- (((uint32_t)pUTF8[i+3] & 0x3F) << 12)|
- (((uint32_t)pUTF8[i+4] & 0x3F) << 6)|
- (((uint32_t)pUTF8[i+5] & 0x3F) << 0);
- cchUnicode++;
- i += 6;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xFC) == 0xF8)//111110xx
- {
- if(i + 5 <= cb)
- {
- *pChr++ =
- (((uint32_t)pUTF8[i+0] & 0x03) << 24)|
- (((uint32_t)pUTF8[i+1] & 0x3F) << 18)|
- (((uint32_t)pUTF8[i+2] & 0x3F) << 12)|
- (((uint32_t)pUTF8[i+3] & 0x3F) << 6)|
- (((uint32_t)pUTF8[i+4] & 0x3F) << 0);
- cchUnicode++;
- i += 5;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xF8) == 0xF0)//11110xxx
- {
- if(i + 4 <= cb)
- {
- *pChr++ =
- (((uint32_t)pUTF8[i+0] & 0x07) << 18)|
- (((uint32_t)pUTF8[i+1] & 0x3F) << 12)|
- (((uint32_t)pUTF8[i+2] & 0x3F) << 6)|
- (((uint32_t)pUTF8[i+3] & 0x3F) << 0);
- cchUnicode++;
- i += 4;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xF0) == 0xE0)//1110xxxx
- {
- if(i + 3 <= cb)
- {
- *pChr++ =
- (((uint32_t)pUTF8[i+0] & 0x0F) << 12)|
- (((uint32_t)pUTF8[i+1] & 0x3F) << 6)|
- (((uint32_t)pUTF8[i+2] & 0x3F) << 0);
- cchUnicode++;
- i += 3;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xE0) == 0xC0)//110xxxxx
- {
- if(i + 2 <= cb)
- {
- *pChr++ =
- (((uint32_t)pUTF8[i+0] & 0x1F) << 6)|
- (((uint32_t)pUTF8[i+1] & 0x3F) << 0);
- cchUnicode++;
- i += 2;
- }
- else
- break;
- }
- else if((pUTF8[i] & 0xC0) == 0x80)//10xxxxxx
- {
- //遇到高2位是10的字符,这是不应该出现的。
- return 0;
- }
- else if((pUTF8[i] & 0x80) == 0x00)//0xxxxxxx
- {
- *pChr++ = pUTF8[i] & 0x7F;
- cchUnicode++;
- i++;
- }
- }
- return cchUnicode;
- }
复制代码 测试代码:- #include"wcs2utf8.h"
- #include<stdio.h>
- #include<locale.h>
- #include<malloc.h>
- #include<string.h>
- #include<Windows.h>
- int main(int argc,char**argv)
- {
- char*pszUTF8;
- size_t cbUTF8;
- //要注意wchar_t的大小不一定是2
- wchar_t wstr[] = L"蛤蛤蛤!我是wchar_t字符串!\n";
- size_t cchwstr = wcslen(wstr);
- wchar_t wcBuf[999] = {0};//测试用缓冲区
- //不加这个不能显示Unicode字符串
- setlocale(LC_ALL, ".ACP");
- //显示字符串
- fputs("这是原始的字符串:\n",stderr);
- fputws(wstr,stdout);
- //用自己的函数转换字符串
- cbUTF8 = _u16toutf8(NULL,(uint16_t*)wstr,cchwstr);
- pszUTF8 = (char*)malloc(cbUTF8);//没有'\0'结尾
- if(!pszUTF8)
- {
- fputs("额..\n",stderr);
- return 1;
- }
- _u16toutf8(pszUTF8,(uint16_t*)wstr,cchwstr);
- //然后用WinAPI测试它对不对
- MultiByteToWideChar(CP_UTF8, 0, pszUTF8, cbUTF8, wcBuf, 999);
-
- //显示字符串
- fputs("这是用MultiByteToWideChar把UTF-8字符串转换成Unicode的字符串:\n",stderr);
- fputws(wcBuf,stdout);
- //然后我们再测试用自己的函数将UTF-8字符串转换为Unicode
- _utf8tou16((uint16_t*)wcBuf, pszUTF8, cbUTF8);
- fputs("这是用_utf8tou16把UTF-8字符串转换成Unicode的字符串:\n",stderr);
- fputws(wcBuf,stdout);
-
- free(pszUTF8);
- return 0;
- }
复制代码
完整源码下载:
utf8test.7z
(3.69 KB, 下载次数: 0, 售价: 4 个宅币)
相关参考资料:
RFC 3629
https://zh.wikipedia.org/wiki/UTF-8 |
|