📄 utf-8 and unicode faq.htm
字号:
它们在 文件名和其他 C 库函数参数里都有特别的含义. 另外, 大多数使用 ASCII 文件的 UNIX 下的工具, 如果不进行重大修改是无法读取 16
位的字符的. 基于这些原因, 在文件名, 文本文件, 环境变量等地方, <STRONG>UCS-2</STRONG> 不适合作为 <STRONG><B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B></STRONG> 的外部编码.</P>
<P>在 ISO 10646-1 <A
href="http://www.cl.cam.ac.uk/~mgk25/ucs/ISO-10646-UTF-8.html">Annex R</A> 和 <A
href="ftp://ftp.funet.fi/mirrors/nic.nordu.net/rfc/rfc2279.txt">RFC 2279</A>
里定义的 <STRONG>UTF-8</STRONG> 编码没有这些问题. 它是在 Unix 风格的操作系统下使用 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 的明显的方法.</P>
<P>UTF-8 有一下特性:
<UL>
<LI>UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位
ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.
<LI>所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0x00-0x7F)
不可能作为任何其他字符的一部分.
<LI>表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在
0x80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.
<LI>可以编入所有可能的 2<SUP>31</SUP>个 UCS 代码
<LI>UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.
<LI>Bigendian UCS-4 字节串的排列顺序是预定的.
<LI>字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到. </LI></UL>
<P>下列字节串用来表示一个字符. 用到哪个串取决于该字符在 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 中的序号.</P>
<DIV align=center>
<CENTER>
<TABLE border=1>
<TBODY>
<TR>
<TD>U-00000000 - U-0000007F: </TD>
<TD>0<I>xxxxxxx</I> </TD></TR>
<TR>
<TD>U-00000080 - U-000007FF: </TD>
<TD>110<I>xxxxx</I> 10<I>xxxxxx</I> </TD></TR>
<TR>
<TD>U-00000800 - U-0000FFFF: </TD>
<TD>1110<I>xxxx</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I> </TD></TR>
<TR>
<TD>U-00010000 - U-001FFFFF: </TD>
<TD>11110<I>xxx</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I> </TD></TR>
<TR>
<TD>U-00200000 - U-03FFFFFF: </TD>
<TD>111110<I>xx</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I>
10<I>xxxxxx</I> </TD></TR>
<TR>
<TD>U-04000000 - U-7FFFFFFF: </TD>
<TD>1111110<I>x</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I> 10<I>xxxxxx</I>
10<I>xxxxxx</I> 10<I>xxxxxx</I> </TD></TR></TBODY></TABLE></CENTER></DIV>
<P>xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义. 只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中,
第一个字节的开头"1"的数目就是整个串中字节的数目.</P>
<P><STRONG>例如</STRONG>: <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 字符 U+00A9 = 1010
1001 (版权符号) 在 UTF-8 里的编码为:</P>
<BLOCKQUOTE>
<P>11000010 10101001 = 0xC2 0xA9</P></BLOCKQUOTE>
<P>而字符 U+2260 = 0010 0010 0110 0000 (不等于) 编码为:</P>
<BLOCKQUOTE>
<P>11100010 10001001 10100000 = 0xE2 0x89 0xA0</P></BLOCKQUOTE>
<P>这种编码的官方名字拼写为 UTF-8, 其中 UTF 代表 <STRONG>U</STRONG>CS
<STRONG>T</STRONG>ransformation <STRONG>F</STRONG>ormat. 请勿在任何文档中用其他名字 (比如 utf8
或 UTF_8) 来表示 UTF-8, 当然除非你指的是一个变量名而不是这种编码本身.</P>
<H2>什么编程语言支持 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B>?</H2>
<P>在大约 1993 年之后开发的大多数现代编程语言都有一个特别的数据类型, 叫做 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B>/ISO 10646-1 字符. 在
Ada95 中叫 Wide_Character, 在 Java 中叫 char.</P>
<P>ISO C 也详细说明了处理多字节编码和宽字符 (wide characters) 的机制, 1994 年 9 月 <A
href="http://www.lysator.liu.se/c/na1.html">Amendment 1 to ISO C</A> 发表时又加入了更多.
这些机制主要是为各类东亚编码而设计的, 它们比处理 UCS 所需的要健壮得多. UTF-8 是 ISO C 标准调用多字节字符串的编码的一个例子,
<EM>wchar_t</EM> 类型可以用来存放 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 字符.</P>
<H2>在 Linux 下该如何使用 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B>?</H2>
<P>在 UTF-8 之前, 不同地区的 Linux 用户使用各种各样的 ASCII 扩展. 最普遍的欧洲编码是 ISO 8859-1 和 ISO
8859-2, 希腊编码 ISO 8859-7, 俄国编码 KOI-8, 日本编码 EUC 和 Shift-JIS, 等等. 这使得 文件的交换非常困难,
且应用软件必须特别关心这些编码的不同之处.</P>
<P>最终, <B style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 将取代所有这些编码,
主要通过 UTF-8 的形式. UTF-8 将应用在
<UL>
<LI>文本文件 (源代码, HTML 文件, email 消息, 等等)
<LI>文件名
<LI>标准输入与标准输出, 管道
<LI>环境变量
<LI>剪切与粘贴选择缓冲区
<LI>telnet, modem 和到终端模拟器的串口连接
<LI>以及其他地方以前用ASCII来表示的字节串 </LI></UL>
<P>在 UTF-8 模式下, 终端模拟器, 比如 xterm 或 Linux console driver, 将每次按键转换成相应的 UTF-8 串,
然后发送到前台进程的 stdin 里. 类似的, 任何进程在 stdout 上的输出都将发送到终端模拟器, 在那里用一个 UTF-8 解码器进行处理,
之后再用一种 16 位的字体显示出来.</P>
<P>只有在功能完善的多语言字处理器包里才可能有完全的 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 功能支持. 而广泛用在 Linux
里用于取代 ASCII 和其他 8 位字符集的方案则要简单得多. 第一步, Linux 终端模拟器和命令行工具将只是转变到 UTF-8. 这意味着只用到 级别1
的 ISO 10646-1 实现 (没有组合字符), 且只支持那些不需要更多处理的语言象 拉丁, 希腊, 斯拉夫 和许多科学用符号. 在这个级别上, UCS
支持与 ISO 8859 支持类似, 唯一显著的区别是现在我们有几千种字符可以用了, 其中的字符可以用多字节串来表示.</P>
<P>总有一天 Linux 会当然地支持组合字符, 但即便如此, 对于组合字符串, 预作字符(如何可用的话)仍将是首选的. 更正式地, 在 Linux 下用
<B style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 对文本编码的首选的方法应该是定义在
<A href="http://www.unicode.org/unicode/reports/tr15/"><B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> Technical Report
#15</A> 里的 <EM>Normalization Form C.</EM></P>
<P>在今后的一个阶段, 人们可以考虑增加在日文和中文里用到的双字节字符的支持 (他们相对比较简单), 组合字符支持, 甚至也许对从右至左书写的语言如希伯来文
(他们可不是那么简单的) 的支持. 但对这些高级功能的支持不应该阻碍简单的平板 UTF-8 在 拉丁, 希腊, 斯拉夫和科学用符号方面的快速应用,
以取代大量的欧洲 8 位编码, 并提供一个象样的科学用符号集.</P>
<H2>我该怎样修改我的软件?</H2>
<P>有两种途径可以支持 UTF-8, 我称之为软转换与硬转换. 软转换时, 各处的数据均保存为 UTF-8 形式, 因而需要修改的软件很少. 在硬转换时,
程序将读入的 UTF-8 数据转换成宽字符数组, 以在应用程序内部处理. 在输出时, 再把字符串转换回 UTF-8 形式.</P>
<P>大多数应用程序只用软转换就可以工作得很好了. 这使得将 UTF-8 引入 Unix 成为切实可行的. 例如, 象 cat 和
<SAMP>echo</SAMP> 这样的程序根本不需要修改. 他们仍然可以对输入输出的是 ISO 8859-2 还是 UTF-8 一无所知,
因为它们只是搬运字节流而没有处理它们. 它们只能识别 ASCII 字符和象 '\n' 这样的控制码, 而这在 UTF-8 下也没有任何改变. 因此,
这些应用程序的 UTF-8 编码与解码将完全在终端模拟器里完成.</P>
<P>而那些通过数字节数来获知字符数量的程序则需要一些小修改. 在 UTF-8 模式下, 它们必须不数入 0x80 到 0xBF 范围内的字节,
因为这些只是跟随字节, 它们本身并不是字符. 例如, <SAMP>ls</SAMP> 程序就必须要修改, 因为它通过数文件名中字符数来排放给用户的目录表格布局.
类似地, 所有的假定其输出为定宽字体, 并因此而格式化它们的程序, 必须学会怎样数 UTF-8 文本中的字符数. 编辑器的功能, 如删除单个字符,
必须要作轻微的修改, 以删除可能属于该字符的所有字节. 受影响有编辑器 (<SAMP>vi,emacs</SAMP>, 等等)以及使用
<SAMP>ncurses</SAMP> 库的程序.</P>
<P>Linux 核心使用软转换也可以工作得很好, 只需要非常微小的修改以支持 UTF-8. 大多数处理字符串的核心功能 (例如: 文件名, 环境变量, 等等)
都不受影响. 下列地方也许必须修改:
<UL>
<LI>控制台显示与键盘驱动程序 (另一个 VT100 模拟器) 必须能编码和解码 UTF-8, 必须要起码支持 <B
style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 字符集的几个子集. 从 Linux
1.2 起这些功能已经有了.
<LI>外部文件系统驱动程序, 例如 VFAT 和 WinNT 必须转换文件名字符编码. UTF-8 已经加入可用的转换选项的列表里了, 因此
<SAMP>mount</SAMP> 命令必须告诉核心驱动程序用户进程希望看到 UTF-8 文件名. 既然 VFAT 和 WinNT 无论如何至少已经用了
<B style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B>了, 那么 UTF-8
在这里就可以发挥其优势, 以保证转换中无信息损失.
<LI>POSIX 系统的 tty 驱动程序支持一种 "cooked" 模式, 有一些原始的行编辑功能. 为了让字符删除功能工作正常,
<SAMP>stty</SAMP> 必须在 tty 驱动程序里设置 UTF-8 模式, 因此它就不会把 0x80 到 0xBF 范围内的跟随字符也数进去了.
<A href="http://clisp.cons.org/~haible/">Bruno Haible</A> 那里已经有了一些
<SAMP>stty</SAMP> 和核心 tty 驱动 程序的 <A
href="ftp://ftp.ilog.fr/pub/Users/haible/utf8/">Linux 补丁 </A>了. </LI></UL>
<H2>C 对 <B style="COLOR: black; BACKGROUND-COLOR: #ffff66">Unicode</B> 和 UTF-8
的支持</H2>
<P>从 GNU glibc 2.1 开始, <SAMP>wchar_t</SAMP> 类型已经正式定为只存放独立于当前 locale 的, 32位的 ISO
10646 值. glibc 2.2 开始将完全支持 ISO C 中的多字节转换函数 (wprintf(),mbstowcs(),等等), 这些函数可以用于在
wchar_t 和包括 UTF-8 在内的任何依赖于 locale 的多字节编码间进行转换.</P>
<P>例如, 你可以写</P><PRE> wprintf(L"Sch鰊e Gr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -