什么是字符编码,为什么我应该打扰它
我对字符编码的概念很困惑。
什么是Unicode,GBK等? 编程语言如何使用它们?
我需要打扰他们吗? 有没有更简单或更快的编程方式,而不必麻烦自己呢?
(请注意,我正在松散地/通俗地使用这些术语中的一些来解释一个简单的问题,但它仍然是关键点。)
一个字节只能有256个不同的值,即8位。
由于在字符集中有超过256个字符的字符集,所以一般不能简单地说每个字符都是一个字节。
因此,必须有描述如何将字符集中的每个字符转换为字节序列的映射。 一些字符可能被映射到单个字节,但其他字符必须映射到多个字节。
这些映射是编码,因为它们告诉你如何将字符编码成字节序列。
至于Unicode,在很高的层面上,Unicode是为每个字符分配一个唯一的编号。 显然这个数字必须比一个字节宽一些,因为有超过256个字符:) Java使用Unicode的版本,其中每个字符被分配一个16位的值(这就是为什么Java字符是16位宽并且具有整数值从0到65535)。 当获得Java字符的字节表示forms时,必须告诉JVM您要使用的编码,以便知道如何select字符的字节序列。
ASCII是基本的
最初1个字符总是被存储为1个字节。 一个字节(8位)可能有256个可能的值。 但实际上只使用了前7位 。 所以只定义了128个字符。 这个集合被称为ASCII字符集 。
-
0x00
–0x1F
包含引导代码(例如CR,LF,STX,ETX,EOT,BEL,…) -
0x20
–0x40
包含数字和标点符号 -
0x41
–0x7F
主要包含字母字符 -
0x80
–0xFF
第8位=未定义。
法语,德语和许多其他语言需要额外的字符。 (例如à, é, ç, ô, ...
),这些字符在ASCII字符集中不可用。 所以他们用第8位来定义他们的angular色。 这就是所谓的“ 扩展ASCII ”。
问题在于额外的1位没有足够的能力覆盖世界上所有的语言。 所以每个地区都有自己的ASCII变体。 有很多扩展的ASCII编码( latin-1
是一个非常受欢迎的编码)。
热门问题: “ASCII是字符集还是编码” ? ASCII
是一个字符集。 然而,在编程中, charset
和encoding
被广泛地用作同义词。 如果我想引用仅包含ASCII字符的编码(第8位始终为0),那就是US-ASCII
。
Unicode更进一步
Unicode也是一个字符集(不是编码) 。 它使用与ASCII标准相同的字符,但是它扩展了附加字符的列表,这使得每个字符的格式为u+xxxx
。 它具有包含全世界使用的所有字符(和stream行的图标)的雄心。
UTF-8,UTF-16和UTF-32是应用Unicode字符表的编码。 但是如何对它们进行编码,他们每个人都有一些不同的方法。 编码一个ASCII字符时,UTF-8将只使用1个字节,给出与任何其他ASCII编码相同的输出。 但是对于其他字符,它将使用第一位来指示第二个字节将跟随。
GBK是一种编码,就像UTF-8使用多个字节一样。 第一个字节遵循ASCII标准,所以只用了7位。 第8位用来表示第二个字节的存在,用来表示大约22,000个汉字。 但是一个重要的区别是,这不尊重Unicode字符集 。
MIMEtypes
MIMEtypes也经常与编码混淆。
没有直接的方法来解码文件。 如果所有的文件都包含一个前缀来表明它们的数据被存储在什么编码中,那么这将是理想的。最后,由应用程序(或其开发者)决定编码(例如US-ASCII
, UTF-8
,系统默认…)。
当通过互联网发送数据时也存在同样的问题。 幸运的是, 一些协议(如HTTP)使用MIMEtypes声明来指定数据使用的是什么types的数据和字符集 。 一个典型的HTTP头包含这个:
Content-Type: text/html; charset=utf-8
但是对于text/xml
来说是毫无意义的(charset参数甚至会被忽略)。 通常,XMLparsing器将读取文件的第一行,查找<?xml encoding=...
标记。 如果在那里,那么他们将使用该编码重新打开该文件。
发送电子邮件时也存在同样的问题。 电子邮件可以包含一个html消息或纯文本。
快捷键
对于Java(以及其他许多编程语言),除了编码的危险之外,还有将字节和整数转换为字符的复杂性,因为它们的内容存储在不同的范围中。
- 一个字节被存储为有符号的字节(范围:
-128
到127
)。 - java中的
char
types存储在2个无符号字节(范围:0
–65535
) - 一个stream返回一个范围在
-1
到255
的整数。
如果你知道你的数据只包含ASCII值。 然后用适当的技巧,你可以从字节parsing你的数据到字符,或者立即在string中包装它们。
// the -1 indicates that there is no data int input = stream.read(); if (input == -1) throw new EOFException(); // bytes must be made positive first. byte myByte = (byte) input; int unsignedInteger = myByte & 0xFF; char ascii = (char)(unsignedInteger);
java中的快捷方式是使用读者和作者,并在实例化时指定编码。
// wrap your stream in a reader. // specify the encoding // The reader will decode the data for you Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
正如之前对XML文件所解释的,这并不重要,因为任何体面的DOM或JAXB编组器都将检查编码属性。
字符编码是用来解决为使用与您不同的语言的人编写软件的问题。
你不知道这些angular色是怎么样的,他们是如何被定购的。 因此,你不知道这种新语言中的string在二进制文件中看起来是什么样的,坦率地说,你不在乎。
你所拥有的是一种将你所说的语言与他们所说的语言(比如译者)进行翻译的方式。 您现在需要一个能够以二进制forms表示两种语言而无冲突的系统。 编码就是这个系统。
这就是允许你编写软件的方式,不pipe二进制语言是怎样表示的。