2

我有一个包含混合二进制和 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];
4

2 回答 2

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。

于 2013-06-24T21:20:28.543 回答
2

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

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

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

于 2013-06-24T21:07:30.207 回答