什么是字符编码,为什么我要打扰它

hgu*_*ser 33 encoding character-encoding

我对字符编码的概念很困惑.

什么是Unicode,GBK等?编程语言如何使用它们?

我需要打扰他们吗?是否有更简单或更快速的编程方式,而不必麻烦自己?

Qua*_*nic 38

(请注意,我正在松散地/通俗地使用这些术语中的一些用于更简单的解释,但仍然是关键点.)

一个字节只能有256个不同的值,即8位.

由于字符集中存在超过256个字符的字符集,因此通常不能简单地说每个字符是一个字节.

因此,必须有映射描述如何将字符集中的每个字符转换为字节序列.某些字符可能映射到单个字节,但其他字符必须映射到多个字节.

这些映射是编码,因为它们告诉您如何将字符编码为字节序列.

至于Unicode,在非常高的层次上,Unicode是尝试为每个字符分配一个唯一的数字.显然,这个数字必须比一个字节宽,因为有超过256个字符:) Java使用Unicode版本,其中每个字符都分配了一个16位值(这就是为什么Java字符是16位宽并且有整数的原因值从0到65535).当您获得Java字符的字节表示时,您必须告诉JVM您要使用的编码,以便它知道如何选择字符的字节序列.


bvd*_*vdb 35

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位来定义他们的角色.这就是所谓的" 扩展ASCII ".

问题是额外的1位没有足够的容量来覆盖世界上所有的语言.因此每个区域都有自己的ASCII变体.有许多扩展的ASCII编码(latin-1非常受欢迎的编码).

热门问题:"ASCII是字符集还是编码"ASCII是一个字符集.但是,在编程中charset并被encoding广泛用作同义词.如果我想引用一个只包含ASCII字符的编码而已(仅第8位始终为0):那就是US-ASCII.

Unicode更进了一步

Unicode是字符集的一个很好的例子 - 而不是编码.它使用与ASCII标准相同的字符,但它使用附加字符扩展列表,这为每个字符提供了格式的代码点u+xxxx.它的目标是包含整个世界中使用的所有角色(和流行的图标).

UTF-8,UTF-16和UTF-32是应用Unicode字符表的编码.但是它们在如何编码它们方面各有不同.UTF-8在编码ASCII字符时仅使用1个字节,提供与任何其他ASCII编码相同的输出.但对于其他字符,它将使用第一个位来指示第二个字节将跟随.

GBK是一种编码,就像UTF-8使用多个字节一样.原理基本相同.第一个字节遵循ASCII标准,因此只使用7位.但就像UTF-8一样,第8位可用于指示第二个字节的存在,然后它用于编码22,000个中文字符之一.主要区别在于,这不遵循Unicode字符集,相比之下它使用了一些中文字符集.

解码数据

对数据进行编码时,使用编码,但在解码数据时,您需要知道使用了哪种编码,并使用相同的编码对其进行解码.

不幸的是,编码并不总是被声明或指定.如果所有文件都包含一个前缀来指示其数据的存储编码,那将是理想的.但在许多情况下,应用程序只需要假设或猜测应该使用哪种编码.(例如,他们使用操作系统的标准编码).

仍然缺乏对此的认识,因为仍有许多开发人员甚至不知道编码是什么.

哑剧类型

Mime类型有时与编码混淆.它们是接收器识别何种数据到达的有用方式.以下是HTTP协议如何使用mime类型声明定义其内容类型的示例.

Content-Type: text/html; charset=utf-8
Run Code Online (Sandbox Code Playgroud)

这是另一个混​​乱的重要来源.MIME类型描述什么样的数据的一个消息包含(例如text/xml,image/png...).在某些情况下,它还将描述数据是如何编码的(即charset=utf-8).2点困惑:

  1. 并非所有mime类型都声明编码.在某些情况下,它只是可选的,有时甚至完全没有意义.
  2. 语法charset=utf-8混淆了语法,因为如前所述,UTF-8是一种编码,而不是一种字符集.但正如前面所解释的,有些人只是交替使用这两个词.

例如,在text/xml声明编码(并且charset简单地忽略参数)的情况下是没有意义的.相反,XML解析器通常会读取文件的第一行,查找<?xml encoding=...标记.如果它在那里,那么他们将使用该编码重新打开文件.

发送电子邮件时存在同样的问题.电子邮件可以包含HTML消息或纯文本.同样在那种情况下,mime类型用于定义内容的类型.

但总的来说,mime类型并不总是足以解决问题.

编程语言中的数据类型

对于Java(以及许多其他编程语言)以及编码的危险,还有将字节和整数转换为字符的复杂性,因为它们的内容存储在不同的范围内.

  • 一个字节存储为有符号字节(范围:-128to 127).
  • charjava中的类型存储在2个无符号字节中(范围:0- 65535)
  • 流返回范围内的整数-1,以255.

如果您知道您的数据仅包含ASCII值.然后使用适当的技能,您可以将数据从字节解析为字符或立即将它们包装在字符串中.

// 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);
Run Code Online (Sandbox Code Playgroud)

快捷键

java中的快捷方式是使用reader和writer,并在实例化时指定编码.

// 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);
Run Code Online (Sandbox Code Playgroud)

正如之前对XML文件所解释的那样,并不重要,因为任何体面的DOM或JAXB编组器都会检查编码属性.

  • 是的,这是一个映射,用简单的英语来说就是字符及其代码点的**列表**。(即带有间隙的编号列表)无论如何,称其为“列表”,称其为“地图”,但为了避免混淆,只是不要称其为“编码”,这就是我的观点。因为 Unicode 和 UTF-8 是不可互换的。它们是两种不同的东西。在我的词汇中:将字符映射到代码点不是编码,这只是一个字符集。- 讨论结束(我真的发现有关语义的讨论是浪费时间)。 (2认同)