在格式转换中,对于字符的处理,需要知道几种编码格式。下面这两篇博客对unicode,utf-8有比较详细的描述。
https://blog.csdn.net/qq_24326765/article/details/82183167
这篇博客讲的是,首先从内存中读入一个字符,然后将字符通过格式转换,转成另一种格式的字符串(16进制)。
这里会用到几个关键技术:
Unicode 与 UTF-8 互转
1. UTF-8 的编码规则是:
① 对于单字节的符号,字节的第一位设为 0,后面的7位为这个符号的 Unicode 码,因此对于英文字母,UTF-8 编码和 ASCII 码是相同的。
② 对于n字节的符号(n>1),第一个字节的前 n 位都设为 1,第 n+1 位设为 0,后面字节的前两位一律设为 10,剩下的没有提及的二进制位,全部为这个符号的 Unicode 码 。
举个例子:比如说一个字符的 Unicode 编码是 130,显然按照 UTF-8 的规则一个字节是表示不了它(因为如果是一个字节的话前面的一位必须是 0),所以需要两个字节(n = 2)。
根据规则,第一个字节的前 2 位都设为 1,第 3(2+1) 位设为 0,则第一个字节为:110X XXXX,后面字节的前两位一律设为 10,后面只剩下一个字节,所以后面的字节为:10XX XXXX。
所以它的格式为 110XXXXX 10XXXXXX 。
那么对于一个具体的 Unicode 编号,具体怎么进行 UTF-8 的编码呢?
首先找到该 Unicode 编号所在的编号范围,进而可以找到与之对应的二进制格式,然后将该 Unicode 编号转化为二进制数(去掉高位的 0),最后将该二进制数从右向左依次填入二进制格式的 X 中,如果还有 X 未填,则设为 0 。
比如:“马”的 Unicode 编号是:0x9A6C,整数编号是 39532,对应第三个范围(2048 - 65535),其格式为:1110XXXX 10XXXXXX 10XXXXXX,39532 对应的二进制是 1001 1010 0110 1100,将二进制填入进入就为:
11101001 10101001 10101100 。
2. 将UTF-8转换成Unicode
继续拿上面的数值举例,现在有一个UTF-8编码为1110XXXX 10XXXXXX 10XXXXXX的字符,如何转换成Unicode?
UTF-8: 11101001 10101001 10101100
(1) 将*current_char指向低位地址的11101001,*(current_char+1)则指向的是中间字节10101001, *(current_char+2)则指向的是高位的10101100
(2) 转换第一个字节:
*current_char & 0x0F << 4 得到-> 10010000,*(current+1) &0x3C >>2 得到->00001010,接着
(*current_char & 0x0F << 4) | (*(current+1) &0x3C >>2) -> 10011010
(3) 转换第二个字节:
*(current+1) &0x03 << 6 得到->01000000,*(current+2) &0x3F>>2 得到->00101100,接着
(*(current+1) &0x03 << 6) | (*(current+2) &0x3F>>2) ->01101100
(4) 拼接两个字节:
char *unicode;
sprintf(unicode, "\\u%02X02X", (*current_char & 0x0F << 4) | (*(current+1) &0x3C >>2),
(*(current+1) &0x03 << 6) | (*(current+2) &0x3F>>2)))
下面是简化的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int dec2hex(char *in);
int main(void)
{
//输入一个字符串
int i, str_len;
char *str = (char *)malloc(sizeof(char) * 12);
str = "hello";
char *current_char; //当前字符
printf("size of str = %d.\n", str_len = strlen(str));
//将每一个字符放入指针
for (i = 0; i < str_len; i++) {
current_char = &str[i];
printf("before convert, current_char[%d] = %c. 0d = %d. \n", i, *current_char, (int)*current_char);
dec2hex(current_char);
}
//输出一个utf8
free(str);
return 0;
}
int dec2hex(char *in)
{
char *utf8 = (char*)malloc(sizeof(char)*8);
sprintf(utf8, "\\u%02X", (0x0F & *in) << 4);
printf("after convert, current_char = %s.\n", utf8);
return 0;
}
与运算
0,1 和 1 做与运算都得到自身,因此0x0F & char,就是取char的低四位
移位
经过与运算取到char的低四位后,<<4,左移4位,即把char的低四位顶到了高四位,原来的低四位补零
如0110 1100 & 0x0F => 0000 1100 << 4 => 1100 0000
结果:
size of str = 5.
before convert, current_char[0] = h. 0d = 104.
after convert, current_char = \u80.
before convert, current_char[1] = e. 0d = 101.
after convert, current_char = \u50.
before convert, current_char[2] = l. 0d = 108.
after convert, current_char = \uC0.
before convert, current_char[3] = l. 0d = 108.
after convert, current_char = \uC0.
before convert, current_char[4] = o. 0d = 111.
after convert, current_char = \uF0.