Unicode编码

时间:2011-09-07 23:01:59

标签: unicode

我有一个问题,如果程序不先验地知道所使用的编码,程序如何解析字符串。

根据我的理解,UTF-8编码存储1个字节的ASII字符,以及最多6个(我认为是6个)字节的所有其他字符。因此,例如,两个空格将作为0x2020存储在内存中。

然后,程序如何能够确定此字符串与使用UTF-16编码编码的字符串`0x2020之间的差异,该编码对应于单个字符,该字符显然是与有时用于的符号类似的字符。表示数学运算符的伴随(我只是看了here)。

似乎解析器总是必须事先知道字符串的编码。如果是这样,这在实践中如何实施?每个字符串之前是否有一个字节告诉解析器使用了什么编码?

2 个答案:

答案 0 :(得分:7)

通常,不可能仅仅基于可以表示文本的字节流来确定所使用的确切编码。但是,如果某个地方有byte order mark,您至少可以使用它作为正在使用的编码的提示。

但是由于文本的制作者和消费者之间没有任何提示或某种形式的合同/元数据交换,你不能100%肯定。如果您try using a heuristic结束,则可以you get these kinds of problems,然后guessing wrong

如果您想确定,请在文本的生产者和使用者之间设置某种协议或契约,以便知道文本编码方案。您可以对编码方案进行硬编码(例如,您的程序可能会解析UTF-8并且只能解析UTF-8),或者确保文本的生成者始终在前面加上字节顺序标记或专门设计的头字节来传达编码方案。

答案 1 :(得分:4)

  

语言是否始终以特定编码存储字符串   显示功能可以安全地假设字符串已编码,   比方说,使用UTF-8?

取决于语言。

在C#中,是的。 char stringlanguage specification(8.2.1)定义为UTF-16代码单元,因此Encoding始终为UTF-16。 Just like Java.

Ruby 1.9中,字符串是一个字节数组,其中包含Content-Type: text/html; charset=UTF-8

但是在像C这样的前Unicode语言(以及像PHP这样设计糟糕的后Unicode语言)中,字符串只是一个没有编码信息的字节数组。你必须依靠惯例。编写一个使用假定为UTF-8字符串的库和另一个假定使用windows-1252字符串的库的程序是一种真正的有趣的体验。

与所有语言同等相关的问题是:如何确定包含编码文本的字节数组的编码?有几种不同的方法:

编码声明。

在使用MIME类型(特别是SMTP和HTTP)的协议中,您可以声明<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">。在HTML中,您可以使用<meta charset="UTF-8">或更新的<?xml version="1.0" encoding="UTF-8"?>。在XML中,有# -*- coding: UTF-8 -*-。在Python source code中,有.txt

不幸的是,这种声明并不总是准确的。并且它们根本不可用于本地存储的普通Encoding.Default文件,因此必须使用不同的方法。

字节顺序标记(BOM)

将特殊字符U+FEFF放在文件的开头可以区分各种UTF编码。

但它不适用于ISO-8859-x或Windows-125x等传统编码,并不总是与UTF-8一起使用。

验证

有些编码对有效字符串的含义有严格的规定。最着名的是UTF-8,它具有前导/尾随字节的严格分离,禁止“过长”编码等.UTF-32甚至更容易识别,因为Unicode限制为17“平面”意味着每个代码unit必须具有00 {00-10} xx xx(或xx xx {00-10} 00 for little-endian)的形式。

因此,如果文本验证为UTF-8或UTF-32,您可以放心地认为它是。有可能出现误报,但它非常低。

然而,这种方法对于假阳性率过高的UTF-16效果不佳。 ( 的偶数长度字节数组的唯一方法是包含不成对的代理,或U + FFFE或U + FFFF。)

统计分析

使用各种语言/编码组合的字符频率表。这是chardet使用的方法(结合BOM和验证)。

回退到默认编码

当其他所有方法都失败时,请假设ISO-8859-1,windows-1252或{{1}}。