我有一个问题,如果程序事先不知道所使用的编码,它们如何解析字符串。
据我所知,UTF-8编码用1个字节存储ASII字符,而所有其他字符最多用6个字节(我想是6个)。因此,例如,两个空格将作为0x2020存储在内存中。
那么,程序如何能够确定这个字符串和使用UTF-16编码的字符串`0x2020之间的区别,该字符串对应于单个字符,该字符明显类似于数学中有时用于表示运算符的伴随的符号(我刚刚在here中查找了该符号)。
似乎解析器总是必须事先知道字符串的编码。如果是这样,这在实践中是如何实现的?在每个字符串之前是否有一个字节告诉解析器使用了什么编码或其他什么?
发布于 2011-09-08 16:28:50
语言是否总是以某种编码存储字符串,以便显示函数可以安全地假定字符串是使用UTF-8编码的?
In取决于语言。
在C#中,是的。char由language specification (8.2.1)定义为UTF-16代码单元,因此string始终是UTF-16。Just like Java.
在Ruby 1.9中,字符串是一个带有相关Encoding的字节数组。
但是在像C这样的前Unicode语言(以及像PHP这样设计糟糕的后Unicode语言)中,字符串只是一个没有编码信息的字节数组。你必须依赖于约定。编写既使用UTF-8字符串的库又使用windows-1252字符串的库的程序是一种非常有趣的体验。
与所有语言同等相关的一个问题是:如何确定包含编码文本的字节数组的编码?有几种不同的方法:
编码声明。
在使用MIME类型(特别是SMTP和HTTP)的协议中,可以声明Content-Type: text/html; charset=UTF-8。在HTML语言中,您可以使用<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">或较新的<meta charset="UTF-8">。在XML中,有<?xml version="1.0" encoding="UTF-8"?>。在Python source code中,有# -*- coding: UTF-8 -*-。
不幸的是,这样的声明并不总是准确的。而且它们根本不适用于本地存储的纯.txt文件,因此必须使用不同的方法。
字节顺序标记(BOM)
将特殊字符U+FEFF放在文件的开头可以区分不同的UTF编码。
但它不适用于ISO-8859-x或Windows-125x等传统编码,也不总是与UTF-8一起使用。
验证
有些编码对有效字符串的构成有严格的规则。最著名的是UTF-8,它严格分隔前导/尾部字节,禁止“过长”编码等。UTF-32甚至更容易识别,因为Unicode对17个“平面”的限制意味着每个代码单元必须具有00 { 00 -10} xx xx格式(或xx xx {00-10} 00表示小端)。
因此,如果文本被验证为UTF-8或UTF-32,您可以放心地假定它是UTF-8或UTF-32。存在误报的可能性,但这种可能性非常低。
然而,这种方法不适合UTF-16,因为UTF-16的假阳性率太高。(偶数长度字节数组不是有效的UTF-16的唯一方法是包含未配对的替代项,或U+FFFE或U+FFFF。)
统计分析
使用各种语言/编码组合的字符频率表。这是chardet使用的方法(与物料清单和验证结合使用)。
回退到默认编码
当所有其他方法都失败时,假定为ISO-8859-1、windows-1252或Encoding.Default。
发布于 2011-09-08 07:06:17
通常,不可能仅根据可以表示文本的字节流来确定所使用的确切编码。但是,如果某个地方有byte order mark,您至少可以使用它来提示正在使用的编码。
但是,如果没有提示,或者文本的生产者和消费者之间没有某种类型的元数据合同/交换,你就不能百分之百确定。您可以使用try using a heuristic,但如果您最终使用guessing wrong,则可以使用you get these kinds of problems。
如果您想真正确定,请在文本的生产者和消费者之间建立某种协议或契约,以便文本和编码方案是已知的。您可以对编码方案进行硬编码(例如,您的程序可能解析UTF-8且仅解析UTF-8),或者确保文本的生产者始终在前面加上字节顺序标记或专门设计的标题字节来传达编码方案。
https://stackoverflow.com/questions/7341453
复制相似问题