将二进制数据解码为UTF-8时会发生什么?

时间:2013-06-24 21:00:00

标签: cocoa utf-8 nsstring

我有一个包含混合二进制和UTF-8编码数据的文件。

看起来像

-----------------
|  Binary data  |
| (unknown len) |
+---------------+
|   Delimiter   |
+---------------+
|  UTF-8 string |   <--- only relevant part of file
+---------------+
|   Delimiter   |
+---------------+
|  Binary data  |
-----------------

我正在尝试提取文本,而不关心二进制内容。我正在将文件读入一个字符串,将所有内容解码为UTF-8,然后使用NSScanner查找分隔符。

我担心的是,根据二进制数据的内容,将其解码为UTF-8可能会导致某种偏移问题,从而无法找到分隔符。 (假设分隔符之前的数据使下一个序列解析为多个字节,并且它会丢失。)

此代码是否会出现某些内容问题?

NSString *fileContents = [NSString stringWithContentsOfFile:path
                                                   encoding:NSUTF8StringEncoding
                                                      error:NULL];
NSScanner *scanner = [NSScanner scannerWithString:fileContents]
[scanner scanUpToString@"<DELIMITER>" intoString:nil];
// TODO: remove delimiter
NSString *desiredString;
[scanner scanUpToString:@"<DELIMITER2>" intoString:&desiredString];

2 个答案:

答案 0 :(得分:3)

UTF-8多字节序列仅由0x80-0xFF范围内的字节组成,因此,假设您的分隔符字面上如图所示(<DELIMITER><DELIMITER2>),它们完全由可以包含的字符组成不是多字节序列的一部分。 (任何纯ASCII字符串都具有此属性。)

然而,UTF-8序列也是长度标记的。例如,如果你有三字节序列

E2 80 3C

E2表示它是3字节序列的第一个字节,但3C不能是该序列的一部分。一个UTF-8解码器应该抛出一个错误或产生双码点序列U + FFFD U + 003C,但我不会对一个解码器感到惊讶,而这个解码器反而只吃了3C而且只产生了一个替换字符。

因此,你提出的建议是不安全的,你应该(正如oh71zb建议的那样)以二进制形式读取文件,扫描分隔符,提取它们之间的内容,然后才将这些字节解释为UTF-8。

答案 1 :(得分:2)

你是对的,你应该担心。原则上,根据分隔符的选择和UTF-8解码器的实现,分隔符开头的一些字节可能被解码为由前导二进制数据形成的某个unicode字符的最后字节。

在这种情况下,您可能会很幸运,因为<DELIMITER>的字符都符合7位ascii集,而多字节UTF-8字符的所有字节都将具有第8位(高位)设置所有字节(http://en.wikipedia.org/wiki/UTF-8#Description)。 UTF-8解码器不应该抓住&#39;&lt;&#39;除了&#39;&#39;之外的任何事情,但我不会指望它。

将文件内容作为二进制字节数组/缓冲区读取当然是一个好主意,有一个分隔符(并确保它不会突然随机出现在二进制数据的中间)其他一些原因......任何此类事件都应该被转义或二进制数据以某种方式编码,以便它不能包含分隔符),在分隔符之间提取utf-8编码的字符串,然后进行utf-8解码。