C 语言的 `char
' 类型是 8 位的,并且将保持 8 位,因为它表示最小的可寻址数据单元。有多种工具可用
ISO/ANSI C 标准在 1995 年添加的修正案中,包含了一个“宽字符”类型 `wchar_t
',一组类似于 <string.h>
和 <ctype.h>
中的函数(分别在 <wchar.h>
和 <wctype.h>
中声明),以及一组 `char *
' 和 `wchar_t *
' 之间的转换函数(在 <stdlib.h>
中声明)。
关于此 API 的良好参考资料包括
使用此 API 的优点
setlocale(LC_ALL,"");
。此 API 的缺点
`wchar_t
' 可能以 Unicode 编码,也可能不以 Unicode 编码;这取决于平台,有时也取决于区域设置。多字节序列 `char *
' 可能以 UTF-8 编码,也可能不以 UTF-8 编码;这取决于平台,有时也取决于区域设置。
详细来说,以下是 Single Unix 规范 关于 `wchar_t
' 类型的说明:给定进程中的所有宽字符代码都由相等数量的位组成。这与字符形成对比,字符可以由可变数量的字节组成。表示字符的字节或字节序列也可以表示为宽字符代码。因此,宽字符代码为处理文本数据提供了统一的大小。所有位均为零的宽字符代码是空宽字符代码,并终止宽字符字符串。可移植字符集(即 ASCII)中每个成员的宽字符值将等于其用作整数字符常量中的单个字符时的值。其他字符的宽字符代码取决于区域设置和实现。状态转换字节没有宽字符代码表示。
一个特别的后果是,在可移植程序中,你不应该在字符串文字中使用非 ASCII 字符。这意味着,即使你知道 Unicode 双引号的代码是 U+201C 和 U+201D,你也不应该在 C 程序中编写字符串文字 L"\u201cHello\u201d, he said"
或 "\xe2\x80\x9cHello\xe2\x80\x9d, he said"
。相反,使用 GNU gettext,将其写为 gettext("'Hello', he said")
,并创建一个消息数据库 en.po,将 "'Hello', he said" 翻译为 "\u201cHello\u201d, he said"。
以下是对 ISO/ANSI C 工具在各种 Unix 版本上的可移植性的调查。
因此,我建议使用可重启和多线程安全的 wcsr/mbsr 函数,忘记那些没有它们的系统(Irix、HP-UX、AIX),并在那些允许你编译使用这些 wcsr/mbsr 函数的程序的系统(Linux、Solaris、OSF/1)上使用 UTF-8 区域设置插件 libutf8_plug.so(见下文)。
Sun 在 http://www.sun.com/software/white-papers/wp-unicode/ 的“使用 Unicode 的国际化应用程序”部分中给出了类似的建议,即
为了正确地国际化应用程序,请使用以下指南
如果出于某种原因,在某些代码段中,你确实必须假设 `wchar_t' 是 Unicode(例如,如果你想对某些 Unicode 字符进行特殊处理),你应该使该代码段以 is_locale_utf8()
的结果为条件。否则,你将会在不同的区域设置或其他平台上搞砸程序的行为。函数 is_locale_utf8
在 utf8locale.h 中声明,并在 utf8locale.c 中定义。
ISO/ANSI C API 的可移植实现,它支持 8 位区域设置和 UTF-8 区域设置,可以在 libutf8-0.7.3.tar.gz 中找到。
优点
Plan9 操作系统是 Unix 的一个变体,在所有应用程序中使用 UTF-8 作为字符编码。它的宽字符类型称为 `Rune
',而不是 `wchar_t
'。Rob Pike 和 Howard Trickey 编写的库的部分内容可在 ftp://ftp.cdrom.com/pub/netlib/research/9libs/9libs-1.0.tar.gz 中找到。另一个类似的库,由 Alistair G. Crooks 编写,是 ftp://ftp.cdrom.com/pub/NetBSD/packages/distfiles/libutf-2.10.tar.gz。特别是,这些库中的每一个都包含一个 UTF-8 感知的正则表达式匹配器。
此 API 的缺点
Qt-2.0 库 http://www.troll.no/ 包含一个完全 Unicode 的 QString 类。你可以使用成员函数 QString::utf8 和 QString::fromUtf8 来转换为/从 UTF-8 编码的文本。QString::ascii 和 QString::latin1 成员函数不应再使用。
前面提到的库实现了 Unicode 感知的 ASCII 概念版本。以下是一些处理 Unicode 概念的库,例如 titlecase(第三种字母大小写,不同于大写和小写)、标点符号和符号之间的区别、规范分解、组合类、规范排序等。
Mark Leisher 的 ucdata 库 http://crl.nmsu.edu/~mleisher/ucdata.html 处理字符属性、大小写转换、分解、组合类。配套软件包 ure-0.5 http://crl.nmsu.edu/~mleisher/ure-0.5.tar.gz 是一个 Unicode 正则表达式匹配器。
Rodrigo Reyes 的 ustring C++ 库 http://ustring.charabia.net/ 处理字符属性、大小写转换、分解、组合类,并包含一个 Unicode 正则表达式匹配器。
Unicode 国际组件 http://oss.software.ibm.com/icu/。IBM 非常全面的国际化库,具有 Unicode 字符串、资源包、数字格式化器、日期/时间格式化器、消息格式化器、排序等等。支持许多区域设置。可移植到 Unix 和 Win32,但只能在 Linux libc6 上开箱即用编译,而不是 libc5。
GNOME libunicode 库 http://cvs.gnome.org/lxr/source/libunicode/,由 Tom Tromey 等人编写。它涵盖字符集转换、字符属性、分解。
两种转换库可用,它们支持 UTF-8 和大量 8 位字符集
Ulrich Drepper 实现的 iconv,包含在 GNU glibc-2.2 中。 ftp://ftp.gnu.org/pub/gnu/glibc/glibc-2.2.tar.gz。iconv 手册页现在包含在 ftp://ftp.win.tue.nl/pub/linux-local/manpages/man-pages-1.29.tar.gz 中。
Bruno Haible 的可移植 iconv 实现。 ftp://ftp.ilog.fr/pub/Users/haible/gnu/libiconv-1.5.1.tar.gz
Konstantin Chuguev 的可移植 iconv 实现。 <joy@urc.ac.ru> ftp://ftp.urc.ac.ru/pub/local/OS/Unix/converters/iconv-0.4.tar.gz
优点
François Pinard 的 librecode ftp://ftp.gnu.org/pub/gnu/recode/recode-3.6.tar.gz。
优点
缺点
Unicode 国际组件 1.7 http://oss.software.ibm.com/icu/。IBM 的国际化库也具有转换工具,在 `ucnv.h
' 中声明。
优点
缺点
G. Adam Stanislav 的 libutf-8 <adam@whizkidtech.net> 包含一些用于从/向 UTF-8 编码的 `FILE*' 流进行即时转换的函数。 http://www.whizkidtech.net/i18n/libutf-8-1.0.tar.gz
优点
缺点
Java 语言内置了 Unicode 支持。类型 `char' 表示一个 Unicode 字符,而 `java.lang.String' 类表示由 Unicode 字符构建的字符串。
Java 可以通过其窗口系统 AWT 显示任何 Unicode 字符,前提是 1. 你正确设置了 Java 系统属性 "user.language",2. /usr/lib/java/lib/font.properties.language 字体集定义是合适的,并且 3. 安装了该文件中指定的字体。例如,为了显示包含日文字符的文本,你需要安装日文字体并运行 "java -Duser.language=ja ..."。你可以组合字体集:为了同时显示西欧、希腊和日文字符,你需要将文件 "font.properties"(涵盖 ISO-8859-1)、"font.properties.el"(涵盖 ISO-8859-7)和 "font.properties.ja" 的组合到一个文件中。 ??这未经测试??
接口 java.io.DataInput 和 java.io.DataOutput 分别具有名为 `readUTF' 和 `writeUTF' 的方法。但请注意,它们不使用 UTF-8;它们使用修改后的 UTF-8 编码:NUL 字符被编码为双字节序列 0xC0 0x80 而不是 0x00,并且在末尾添加一个 0x00 字节。以这种方式编码,字符串可以包含 NUL 字符,并且仍然不需要以长度字段为前缀 - 可以使用 C <string.h> 函数(如 strlen() 和 strcpy())来操作它们。
Common Lisp 标准指定了两种字符类型:`base-char' 和 `character'。是否支持 Unicode 取决于实现。该语言还指定了一个关键字参数 `:external-format' 给 `open',作为指定字符集或编码的自然位置。
在免费的 Common Lisp 实现中,只有 CLISP http://clisp.cons.org/ 支持 Unicode。你需要 2000 年 3 月或更新版本的 CLISP。 ftp://clisp.cons.org/pub/lisp/clisp/source/clispsrc.tar.gz。类型 `base-char' 和 `character' 都等效于 16 位 Unicode。函数 char-width
和 string-width
提供了与 wcwidth()
和 wcswidth()
相当的 API。用于文件或套接字/管道 I/O 的编码可以通过 `:external-format' 参数指定。用于 tty I/O 的编码和文件/套接字/管道 I/O 的默认编码取决于区域设置。
在商业 Common Lisp 实现中
LispWorks http://www.xanalys.com/software_tools/products/ 支持 Unicode。类型 `base-char' 等效于 ISO-8859-1,类型 `simple-char'(`character' 的子类型)包含所有 Unicode 字符。用于文件 I/O 的编码可以通过 `:external-format' 参数指定,例如 '(:UTF-8)。限制:编码不能用于套接字 I/O。编辑器无法编辑 UTF-8 编码的文件。
Eclipse http://www.elwood.com/eclipse/eclipse.htm 支持 Unicode。请参阅 http://www.elwood.com/eclipse/char.htm。类型 `base-char' 等效于 ISO-8859-1,类型 `character' 包含所有 Unicode 字符。用于文件 I/O 的编码可以通过 `:element-type' 和 `:external-format' 参数的组合指定给 `open'。限制:字符属性函数取决于区域设置。源文件和编译后的源文件不能包含 Unicode 字符串文字。
商业 Common Lisp 实现 Allegro CL 在 6.0 版本中具有 Unicode 支持。类型 `base-char' 和 `character' 都等效于 16 位 Unicode。用于文件 I/O 的编码可以通过 `:external-format' 参数指定,例如 :external-format :utf8
。默认编码取决于区域设置。更多详细信息请访问 http://www.franz.com/support/documentation/6.0/doc/iacl.htm。
Ada95 被设计为支持 Unicode,Ada95 标准库具有特殊的 ISO 10646-1 数据类型 Wide_Character 和 Wide_String,以及许多相关的过程和函数。GNU Ada95 编译器(gnat-3.11 或更新版本)支持 UTF-8 作为宽字符的外部编码。这允许你在源代码和应用程序 I/O 中使用 UTF-8。要在应用程序中激活它,在打开文件时在 FORM 字符串中使用 "WCEM=8",如果源代码是 UTF-8,则使用编译器选项 "-gnatW8"。有关详细信息,请参阅 GNAT (ftp://cs.nyu.edu/pub/gnat/) 和 Ada95 (ftp://ftp.cnam.fr/pub/Ada/PAL/userdocs/docadalt/rm95/index.htm) 参考手册。
Python 2.0 (https://pythonlang.cn/2.0/, https://pythonlang.cn/pipermail/python-announce-list/2000-October/000889.html, http://starship.python.net/crew/amk/python/writing/new-python/new-python.html) 包含 Unicode 支持。它有一个新的基本数据类型 `unicode',表示 Unicode 字符串,一个模块 `unicodedata' 用于字符属性,以及一组用于最重要编码的转换器。有关详细信息,请参阅 http://starship.python.net/crew/lemburg/unicode-proposal.txt,或发行版中的文件 Misc/unicode.txt
。
自 JavaScript 1.3 版本以来,字符串始终是 Unicode。没有字符类型,但你可以在字符串内部使用 \uXXXX 表示法表示 Unicode 字符。内部不进行规范化,因此它期望接收 Unicode 规范化形式 C,这是 W3C 推荐的。有关详细信息,请参阅 http://developer.netscape.com/docs/manuals/communicator/jsref/js13.html#Unicode 和完整的 ECMAscript 规范 http://developer.netscape.com/docs/javascript/e262-pdf.pdf。
Tcl/Tk 从 8.1 版本开始使用 Unicode 作为其基本字符集。其字符串的内部表示形式是 UTF-8。它支持 Unicode 字符的 \uXXXX 表示法。请参阅 http://dev.scriptics.com/doc/howto/i18n.html。
Perl 5.6 在内部以 UTF-8 格式存储字符串,如果你在脚本开头写入
use utf8;
use utf8;
。length()
返回字符串的字符数。有关详细信息,请参阅 Perl-i18n FAQ,网址为 http://rf.net/~james/perli18n.html。通过 iconv 接口模块 http://cpan.perl.org/modules/by-module/Text/Text-Iconv-1.1.tar.gz 可以支持其他(非 8 位)编码。
Tomohiro Kubota 编写了一篇国际化介绍 http://www.debian.org/doc/manuals/intro-i18n/。他的文档重点是编写可在任何区域设置中运行的软件,使用区域设置的编码。