文本在内存中的字符集编码(1)--String 的本质--乱码探源(4)

摘要: 文本在内存中的编码以及 String 类型的本质.

让我们从一个故事开始说起. 话说北大是很有哲学传统的, 当你准备踏进北大校门时, 连门卫都会连问你三个终极哲学问题:

你是谁? 你从哪里来? 你要到哪里去?

那么这与我们的问题又有何关系呢? 我觉得理解内存中的编码的关键在于理解 String 类型, 因此我们也来探讨一下 String 的前世今生:

  • String 是谁(什么)?
  • String 从哪里来?
  • String 到哪里去?

当我们能够清晰地回答这三个终极问题时, 对文本在内存中的编码也算理解得差不多了.

注: 文中将用 Java 平台为例来探讨这些问题.

继续阅读

引入字符集编码信息的一些实践--乱码探源(3)

摘要: 介绍了两种引入编码信息的实践, 变相引入及外部指定.

前面说到, 文本文件中没有编码信息, 导致了各种混乱, 那么, 最关键的就是要指定好所用的编码信息. 具体地讲, 有以下一些途径.

变相引入

什么是变相引入呢? 其实本质与前面提到的一些"文件头"信息是类似的.

xml

我们来看看 xml 文件的例子, 你通常能在最开始看到这样的一行:

<?xml version="1.0" encoding="UTF-8"?>

那么这里面, encoding 指明的就是所用编码的信息了. 可是, 等等!! 为了得到这一编码信息, 我得先读取这一文件;可要正确读取文件, 我又要先知道编码信息!

这成了一个鸡生蛋, 蛋生鸡, 又或者说是先有鸡还是先有蛋的问题了.

怎么破呢? 考虑这一行信息所有字符都是 ASCII 中的字符, 那么我们可以先使用最基础的 ASCII 去读取它开头的一些信息, 获取到这一编码信息后, 再次用这一编码去读取文件即可.

ASCII 可谓是这样一个始祖鸟或者始祖蛋一样的存在.

可以动动手做些实验, 先建立一个 xml 文件, 比如就叫 foo.xml

foo.xml

继续阅读

确定文本文件的字符集编码--乱码探源(2)

摘要: 介绍了如何去确定一个文本文件所使用的编码, 特别地以记事本保存"联通"为例进行了深入分析.

在上一篇中, 探讨了文件名编码以及非文本文件中的文本内容的编码, 在这里, 将介绍更为重要的文本文件的编码.

混乱的现状

设想一下, 如果在保存文本文件时, 也同时把所使用的编码的信息也保存在文件内容里, 那么, 在再次读取时, 确定所使用的编码就容易多了.

很多的非文本文件比如图片文件通常会在文件的头部加上所谓的 "magic number(魔法数字)" 来作为一种标识.

所谓的 "magic number", 其实它就是一个或几个固定的字节构成的固定值, 用于标识文件的种类(类似于签名).

比如 bmp 文件通常会以 "42 4D" 两字节开头.

又比如 Java 的 class 文件, 则是以四字节的 "ca fe ba be" 打头. (咖啡宝贝? )

java class magic number

即便没有文件后缀名, 根据这些信息也是确定一个文件类型的手段.

附: 关于用 Notepad++ 查看十六进制的问题, 这是一个插件, 如果没有装, 菜单--插件--plugin manager--available--HEX-Editor, 装上它.

装上后, 它通常在工具栏的最右边, 一个黑色的大写的斜体的"H"就是它. 单击它可以在正常文本与 16 进制间切换. 要进一步查看二进制, 在文本区, 右键--view in--to binary.

继续阅读

字符集与编码(八)--ASCII 和 ISO-8859-1

摘要: 简单介绍了 ASCII 和 ISO-8859-1 两个常见的字符集(编码).

在前面其实也谈到了 ASCII 了, 但并没有很具体, 作为一个完整系列的一部分, 还是有必要谈一下, 也作为后面讨论的一些基础.

ASCII

它的全称是 American Standard Code for Information Interchange(美国信息交换标准代码), 是一个 7 位字符编码方案. 下面是它的一张简图(来自http://www.asciitable.com/index/asciifull.gif):

ascii table

ASCII 定义了 128 个字符, 包括 33 个不可打印的 控制字符(non-printing control characters) 和 95 个可打印的字符.

继续阅读

字符集与编码(二)--编号 vs 编码

摘要: 编号是字符到最终编码的一个过渡层与抽象层, 起着承上启下的作用, 它与最终编码在形式上也常常很相似, 在 Unicode 中, 码点(code point)扮演的正是编号的角色. 广义而言, 编号其实也是一种编码.

在深入研究 字符集编码, 简称 编码 之前, 我们先引入一个概念: 编号(code), 引入它是为了更好地与 编码(encode) 相区分.

如果你对 Unicode 有深入了解, 你也许已经意识到了 Unicode 中 码点(code point) 扮演的正是 编号 的角色. 类似的还有 GB 系列中所谓的 区位码.

其实叫什么并不重要, 爱咋咋地, 我并不关心. 但乱叫容易叫混了, 比如把 码点 也叫成 Unicode 编码, 这里先把这些归入到 编号 概念. 为区别起见, 用黑色加粗的 编码 特指 字符集编码.

到了后面你甚至会为 字符集编码 的边界在哪而困惑, 为它的准确定义而纠结, 不过到那时你已经属于"难得糊涂"了, 编号 这一概念你也可以把它丢到爪哇国去了.

继续阅读