UTF8原理是啥?如何用C编写UTF8的转换代码?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UTF8原理是啥?如何用C编写UTF8的转换代码?相关的知识,希望对你有一定的参考价值。

参考技术A UTF8并不算是一种电脑编码,而是一种储存和传送的格式,如前所述,每个Unicode/UCS字符都以 2或4个bytes来储存,看看以下的比较:

以"I am Chinese"为例
用ANSI储存:12 Bytes
用Unicode/UCS2储存:24 Bytes + 2 Bytes(header)
用UCS4储存:48 Bytes + 4 Bytes(header)

以"我是中国人"为例
用ANSI储存:10 Bytes
用Unicode/UCS2储存:10 Bytes + 2 Bytes(header)
用UCS4储存:20 Bytes + 4 Bytes(header)

由此可见直接以Unicode/UCS的原始形式来储存是一种极大的浪费,而且也不利于互联网的传输(中文稍为合算一点^_^)。

有见及此,Unicode/UCS的压缩形式--UTF8出现了,套用官方网站的首句话『UTF-8 stands for Unicode Transformation Format-8. It is an octet (8-bit) lossless encoding of Unicode characters.』,由于UTF也适用于编码UCS,故亦可称为『UCS transformation formats (UTF)』

UTF8是以8bits即1Bytes为编码的最基本单位,当然也可以有基于16bits和32bits的形式,分别称为UTF16和UTF32,但目前用得不多,而UTF8则被广泛应用在文件储存和网络传输中。

编码原理

先看这个模板:

UCS-4 range (hex.) UTF-8 octet sequence (binary)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx

编码步骤:
1) 首先确定需要多少个8bits(octets)
2) 按照上述模板填充每个octets的高位bits
3) 把字符的bits填充至x中,字符顺序:低位→高位,UTF8顺序:最后一个octet的最末位x→第一个octet最高位x
4) 解码的原理一样。

实例:(留意每个bit的颜色,粗体字为模板内容)

UCS-4 UTF-8
HEX BIN Bytes BIN HEX Bytes
0000 000A 00001010 4 00001010 0A 1
0000 0099 10011001 4 11000010 10011001 C2 99 2
0000 8D99 10001101 10011001 4 11101000 10110110 10011001 E8 B6 99 3

不知大家看懂了没有,其实不懂也无所谓,反正又不用自己算,程式可以完全代劳。

以UTF8格式储存的文件档首标识为EF BB BF。

效率

从上述编码原理中得出的结论是:
1.每个英文字母、数字所占的空间为1 Byte;
2.泛欧语系、斯拉夫语字母占2 Bytes;
3.汉字占3 Bytes。

由此可见UTF8对英文来说是个非常诱人的方案,但对中文来说则不太合算,无论用ANSI还是 Unicode/UCS2来编码都只用2 Bytes,但用UTF8则需要3 Bytes。

以下是一些统计资料,显示用UTF8来储存文件每个字符所需的平均字节:
1.拉丁语系平均用1.1 Bytes;
2.希腊文、俄文、阿拉伯文和希伯莱文平均用1.7 Bytes;
3.其他大部份文字如中文、日文、韩文、Hindi(北印度语)用约3 Bytes;
4.用超过4 Bytes的都是些非常少用的文字符号

Objective C中的UTF8字符解码

【中文标题】Objective C中的UTF8字符解码【英文标题】:UTF8 character decoding in Objective C 【发布时间】:2011-06-22 06:14:13 【问题描述】:

我试图在我的 iPhone 上解析来自 json 网络服务的提要,但是 utf8 转换没有按应有的方式工作,或者我做错了什么 以下是提要的一部分 est un r\u00c3\u00aave en noir

这是我为转换上述内容而编写的代码:

NSString* str1 = @"est un r \u00c3\u00aa ve en noir";

NSString* str = [NSString stringWithUTF8String:[str1 cStringUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"Converted UTF   %@",str);

这是我得到的输出:Converted UTF est un r ê ve en noir

预期的输出应该是Converted UTF est un rêve en noir

当我检查 UTF 表并在线使用 utf 转换器时,使用相同的代码并使用字符串 @"est un r\u00EAve en noir" 正确获得了输出,但如果我没记错的话,我认为是 UTF16 表示。现在我真的在修复如何解析这个提要。

【问题讨论】:

完美解决方案***.com/questions/6204718/…恭喜... 【参考方案1】:

在经历了很多悲伤之后,我想通了。使用这个。

NSString *correctString = [NSString stringWithCString:[utf8String cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding];

【讨论】:

非常感谢,正是我想要的。 没问题。只是一个警告,我一直有这个解决方案的内存泄漏问题。我认为我用 [NSString stringWithString:(上面的代码)] 修复了 你是救生员。找了这么多小时,我几乎要放弃了。然后,我发现了这段可爱的小代码。非常感谢。这应该是公认的答案。 如果该解决方案适合您,那么您的 JSON 解析器工作不正确,并将传入数据解释为拉丁语 1 而不是 UTF-8。根据您的连接方式,您还应该检查您在 HTTP 标头中获得的内容(尽管 NSJSONSerialization 不接受它们,但它首先会得到正确的答案) 你拯救了我的一天。还有晚上!非常感谢!【参考方案2】:

我认为测试用例坏了;以下:

NSString* str1 = @"est un r \u00c3\u00aa ve en noir";
NSLog(@"%@", str1);

还输出“est un r ê ve en noir”。但是,这个:

NSString* str1 = @"est un rêve en noir";
NSLog(@"%@", str1);

输出“est un rêve en noir”,如下所示:

NSString* str1 = @"est un rêve en noir";

NSString* str = [NSString stringWithUTF8String:[str1 cStringUsingEncoding:NSUTF8StringEncoding]];
NSLog(@"%@", str);

略短的版本也是如此:

NSString* str1 = @"est un rêve en noir";

NSString* str = [NSString stringWithUTF8String:[str1 UTF8Encoding]];
NSLog(@"%@", str);

而且,确实:

char *str1 = "est un r\xc3\xaave en noir";

NSString* str = [NSString stringWithUTF8String:str1];
NSLog(@"%@", str);

我认为这是 JSON 的问题,而不是 UTF8。 \u 后跟四个十六进制数字是 JSON 编码通用 UTF16 字符的方式,它不是 UTF 的固有部分。所以 NSString 不知道如何处理它。您的 JSON 解析器需要适应正确解析转义序列。

【讨论】:

同意,如果 json 输出是实际的 utf-8,那就是,? ?【参考方案3】:

在 iOS 9 中不需要做任何事情。它会自动转换。

   NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
                                                               fromData:postData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 

                                                                   NSLog(@"response header: %@",response);

                                                                   NSString* aStr;
                                                               aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                                               NSLog(@"response data: %@", aStr);

                                                               NSDictionary * json  = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

                                                               for (NSDictionary *dict in json)
                                                               
                                                                   NSLog(@"%@", dict);
                                                                   NSString *name = [dict objectForKey:@"name"];
                                                                   NSString *msg = [dict objectForKey:@"message"];
                                                                   NSString *topic = [dict objectForKey:@"topic"];
                                                                   NSLog(@"*********** %@, %@, %@", name,topic,msg);

                                                                   // now do something
                                                                   

【讨论】:

【参考方案4】:

发送到服务器时

NSString* str1 = @"est un r \u00c3\u00aa ve en noir";
    NSData *str1Data = [str1 dataUsingEncoding:NSNonLossyASCIIStringEncoding];
    NSString  *str2 = [[NSString alloc] initWithData:str1Data encoding:NSUTF8StringEncoding];

收到后可以这样解码

NSData *recivedStrData = [recivedStr dataUsingEncoding:NSUTF8StringEncoding];
    NSString *strResult = [[NSString alloc] initWithData:recivedStrData encoding:NSNonLossyASCIIStringEncoding];

这对我有用!

【讨论】:

以上是关于UTF8原理是啥?如何用C编写UTF8的转换代码?的主要内容,如果未能解决你的问题,请参考以下文章

Objective C中的UTF8字符解码

c语言标准是啥意思,啥ansi utf8是啥

utf-8字符串转成中文如何转换

如何js文件保存为utf-8编码

C语言UTF8要怎样转gb2312

如何用JS将一段十六进制(HEX)字符串转换为汉字?