您好,欢迎访问一九零五行业门户网

关于Windows Notepad里可选的字符编码

下面由notepad教程栏目给大家介绍关于windows notepad里可选的字符编码,希望对需要的朋友有所帮助!
简析windows notepad里可选的字符编码
这篇文章就简单测试一下windows notepad的行为。
▲ windows notepad的编码包含ansi、unicode、unicode big endian和utf-8。
警告本文仅仅阐述一个广泛使用的软件的技术事实,不代表作者支持或反对使用该软件。
事实上作者推荐任何时候都不使用 windows notepad 来处理计算机程序代码。
本文仅在某一个简体中文版64位windows 7的实例下验证,仅供参考。不保证在其他相同或相异系统下能够重现一致的结果。
注意本文严格区分unicode的编码和字节序列化。
unicode的编码仅指使用数(通常写成16进制数)来一对一的代表字符的工作。这个数的范围仅受unicode标准的约束,与计算机毫无关联。
unicode的字节序列化指为了能够写入计算机存储器,而把一个unicode标准范围内的数,表示成n个字节的工作。
测试用例测试用例为:“锟斤拷【断行】a【断行】”。(锟斤拷是一种信仰。)
所有字符的gbk和unicode编码为:
锟 gbk=efbf unicode=u+951f斤 gbk=bdef unicode=u+65a4拷 gbk=bfbd unicode=u+62f7以下ascii字符的gbk和unicode编码与ascii一致:
a=0x61 cr=0x0d lf=0x0a
 (windows一个换行符占有两个字符:cr+lf)
ansi在简体中文系统下,ansi就是中华人民共和国国家标准定义的gbk编码。
windows notepad使用ansi存储这个文件的结果如下:
ef bf  bd ef  bf bd  0d  0a  61  0d  0a-----  -----  -----  --  --  --  --  --
简单的使用gbk编码存储了所有的字符。最高位不是1的单字节并等同于ascii,否则双字节。
这里要注意字节序(endian)的问题[注a]。可以看到这里的字节序是大端在先(big-endian)的。
但是不必特意强调“大端在先的gbk”——因为从gb2312开始,标准就规定了存储方式是大端在先的[注b]。后来的gbk和gb18030-2000向下兼容。
ansi的麻烦就是依赖系统——其他语言系统的ansi就不是gbk了,打开gbk的文件必然乱码。并且gbk的字符集本身也太小。
(千万不要说“我只用中文”——少了unicode那些符号,网上那些颜文字都打不出来)
unicode系列windows notepad所说的“unicode”、“unicode big endian”和utf-8,全都是同样的unicode编码的不同的字节序列化存储方法。
utf-16 和 bom这里的unicode指utf-16[注c]。utf-16是极其简单粗暴的序列化方法——绝大多数的unicode字符都在u+0000~u+ffff的范围内[注d],那就每个字符用两个字节,把unicode编码的原始值写盘。
注意ascii字符也必须浪费一倍的空间存储高8位的0x00——因为如果把高8位的0略了,解析时就再也没有其他的依据去断字。
对于utf-16就存在大端和小端的问题了——utf-16并不规定字节的大端在前还是小端在前。但utf-16并不包含表示字节序的信息,总不能人工看看哪个解析是不乱码的吧……
unicode提供的解决方式是,把一个零宽无断字空格符(u+feff zero width no-break space)以utf-16的方式序列化之后,塞到文件的最前边。这样utf-16解析器读取文件的前两个字节,如果是fe ff就是大端在前,ff fe就是小端在前。
这个塞进去的东西就叫bom(byte order mark,字节顺序标记)。
值得一提的是,零宽无断字空格符也常用于充当1个有效字符,破拆各种场合的字数限制。包括segmentfault的问答和评论内容在内。
记事本的“unicode”和“unicode big endian”单写“unicode”,根本就不是一种存储方法的完整表达。因为这只包含编码而没有字节序列化。
m$出现这种错误,我一点都不觉得奇怪。死记结论就可以了:windows notepad的“unicode”就是utf-16。
windows notepad使用“unicode” = 小端在先的utf-16,存储这个文件的结果如下:
 ff fe 1f 95 a4 65 f7 62 0d 00 0a 00 61 00 0d 00 0a 00 -bom- ----- ----- ----- ----- ----- ----- ----- ----- u+feff  951f  65a4  62f7  000d  000a  0061  000d  000a <--unicode原始值
windows notepad使用“unicode big endian” = 大端在先的utf-16,存储这个文件的结果如下:
 fe ff 95 1f 65 a4 62 f7 00 0d 00 0a 00 61 00 0d 00 0a -bom- ----- ----- ----- ----- ----- ----- ----- ----- u+feff  951f  65a4  62f7  000d  000a  0061  000d  000a <--unicode原始值
utf-8utf-8是一种用1~4个字节表示1个unicode字符的变长的字节序列化方法。具体的实现细节看这篇文章。utf-8的好处在于:
无论是ietf的推荐,还是实际业界的执行,utf-8都是互联网的标准。向下兼容,ascii字符utf-8序列化后仍是原样,任何ascii文件也是有效的utf-8文件。没有字节序问题。utf-8的字节序是由rfc3629定死的。windows notepad使用utf-8存储这个文件的结果如下:
 ef bb bf  e9 94 9f  e6 96 a4  e6 8b b7  0d   0a   61   0d   0a --bom---  --------  --------  --------  --   --   --   --   --u+ feff      951f      65a4      62f7   000d 000a 0061 000d 000a <--unicode原始值
注意utf-8前边仍然塞进去了u+feff按照utf-8序列化的结果ef bb bf,作为前边提到过的bom字节顺序标记。windows notepad存储的utf-8,是带有bom标记的utf-8。
但是如果仅仅对于utf-8而言,字节序是没有意义的。因为utf-8的字节序被规范写死,u+feff编码后必然得到ef bb ff,得不出其他的。没有二义性,bom就失去了原本的意义。也许只有区别utf-8文件和utf-16文件的用处……
如何对待utf-8文件的bom,rfc3629的第6章有详细的规定,不加详述。
值得一提的是,bom我想很多php程序员都经历过并且恨之入骨——php不认识文件中的bom头并会将其作为http response的正文送出。这甚至在无缓冲的情况下,会导致header()等必须在response开始前执行的函数直接失效。
所以php程序员总是会喜欢utf-8 without bom的编码方式——这基本也就宣布了windows下的php开发,windows notepad完全的淘汰出局,哪怕是任何一星半点代码的临时修改。
番外:notepad++的字符编码测试ansi没有区别,但notepad++支持选择多国编码的不同ansi编码方式(类似浏览器里选编码),可以轻松生成或读取shift-jis等其他字符集的文件。适合用于对付日文老游戏的readme等文档。
ucs-2 big endian、ucs-2 little endian和前边utf-16的两个例子一致。注意utf-16的文件不提供“无bom”的存储方法(提供了就坏了)。
utf-8仍然代表“带有bom标记的utf-8”。但同时提供php程序员最爱的utf-8 without bom,就像:
 e9 94 9f  e6 96 a4  e6 8b b7  0d   0a   61   0d   0a --------  --------  --------  --   --   --   --   --u+ 951f      65a4      62f7   000d 000a 0061 000d 000a <--unicode原始值
simple and clean.
注解
[注a] 对于一个双(多)字节的数,一定会按8位截断为1字节后写盘。那么写盘时先写最低8位还是先写最高8位,就是所谓的“字节序”(endian)问题。例如,数0x01020304写盘时,是先写最低8位的04 03 02 01,还是先写最高8位的01 02 03 04?
 先写低8位的叫做小端在先(little-endian),先写高8位的叫做大端在先(big-endian)。实际采用何种字节序受系统环境、标准规范和软件实际编写的多方面控制,不一概而论。
[注b] 字节序如果我没弄错,是gb2312采用的euc字符编码方法控制的。
[注c] 本文并不严格区分utf-16与ucs-2。
[注d] unicode的最大值实际上达到了u+10ffff,超出了两个字节能够存储的限度。
 但unicode由于历史原因,留下了u+d800~u+dfff这一段永久保留不用的空缺区域。
 因此对u+10000及以上的字符,utf-16借助了这部分空缺区域,对这些编码超大的字符打破2字节16位的惯例,特别的用4字节32位去表示之。
 这一部分编码值太大的字符,超出了gbk的字符集范围,因此本文将完全忽略。如有机会再进一步测试。
以上就是关于windows notepad里可选的字符编码的详细内容。
其它类似信息

推荐信息