为什么iconv可以转换"É"的预组成形式而不能转换分解形式(从UTF-8到CP1252)



我使用iconv库从使用UTF-8的现代输入源接口到使用Latin1的传统系统,即CP1252(ISO-8859-1的超集)。

该接口最近未能转换法语字符串"Éeducation",其中"É"被编码为十六进制45 CC 81。请注意,目标编码确实有一个"É"字符,编码为C9

为什么iconv无法转换"É"?我检查了MacOS X 10.7.3提供的iconv命令行工具是否表示无法转换,并且PERL iconv模块也出现了故障。

更令人困惑的是,"É"字符的预编译形式(编码为C3 89)转换得很好。

这是iconv的错误还是我错过了什么?

请注意,如果我尝试从UTF-16转换(其中"É"被编码为00 C9组合或00 45 03 01分解),我也会遇到同样的问题。

不幸的是,iconv确实不处理UTF-8中的分解字符,除了安装在Mac OS X上的版本。

处理Mac文件名时,可以将iconv与"utf8 Mac"字符集选项一起使用。它还考虑了Mac分解形式的一些特性

然而,iconv或libiconv的非mac版本不支持这一点,我找不到mac上使用的提供这种支持的来源。

我同意你的观点,即iconv应该能够处理NFC和NFD形式的UTF8,但在有人修补源之前,我们必须手动检测并处理它,然后再将内容传递给iconv。

面对这个烦人的问题,我使用了Jukka建议的Perl的Unicode::Normalize模块。

#!/usr/bin/perl
use Encode qw/decode_utf8 encode_utf8/;
use Unicode::Normalize;
while (<>) {
    print encode_utf8( NFC(decode_utf8 $_) );
}

在调用iconv之前使用规范化器(在本例中,为规范化表单C)。

一个处理字符编码(字符的不同表示,或者更确切地说,代码点,作为字节序列)和在它们之间转换的程序应该将预编译和组合的形式视为不同的。分解的É是两个代码点,因此与预编译的É不同,后者是一个代码点。

最新更新