为什么Linux中的iconv不能正确地将UTF-8中的西班牙语字符转换为ISO-8859-1

为什么Linux中的iconv不能正确地将UTF-8中的西班牙语字符转换为ISO-8859-1,linux,utf-8,iso-8859-1,iconv,Linux,Utf 8,Iso 8859 1,Iconv,在Linux中,我使用以下命令将UTF-8转换为ISO-8859-1文件: iconv -f UTF-8 -t ISO-8859-1//TRANSLIT input.txt > out.txt 转换后,当我打开out.txt 奎恩·戈麦斯被翻译成奎恩·戈麦斯 为什么é和ó以及其他翻译不正确 在Unicode中有(至少)两种方法来表示重音字母é:作为单个代码点U+00E9,带锐音符的拉丁文小写字母E,以及作为两个字符序列E(U+0065),后跟U+0301,结合锐音符 您的输入文件使用后一

在Linux中,我使用以下命令将
UTF-8
转换为
ISO-8859-1
文件:

iconv -f UTF-8 -t ISO-8859-1//TRANSLIT input.txt > out.txt
转换后,当我打开
out.txt

奎恩·戈麦斯被翻译成奎恩·戈麦斯

为什么
é
ó
以及其他翻译不正确

在Unicode中有(至少)两种方法来表示重音字母
é
:作为单个代码点
U+00E9
,带锐音符的拉丁文小写字母E,以及作为两个字符序列
E
U+0065
),后跟
U+0301
,结合锐音符

您的输入文件使用后一种编码,
iconv
显然无法翻译为拉丁语-1(ISO-8859-1)。有了
//translatit
后缀,它将未经修改地通过未加重音的
e
并删除组合字符

您可能需要转换输入,使其不使用组合字符,将序列
U+0065
U+0301
替换为单个代码点
U+00E9
(以2个字节表示)。要么这样,要么安排生成输入文件的内容首先使用该编码


这就是问题所在;我现在不知道该怎么纠正它。

基思,你说得对。我从Oracle社区Sergiusz Wolicki找到了答案
这里我逐字引用他的答案。我为可能有这个问题的人发帖

“问题在于,您的数据是以Unicode分解形式存储的,这是合法的,但很少用于西欧语言。“é”存储为“e”(0x65=U+0065)加上组合的锐重音(0xcc,0x81=U+0301)。大多数简单的转换工具,包括标准的Oracle客户端/服务器转换,都没有考虑到这一点,也没有将分解的字符转换为ISO 8859-1中的预合成字符。它们尝试独立地转换两个代码中的每一个,产生“e”加上一些替换重音字符的内容,而ISO 8859中不存在重音字符-1.您可以在SQL Developer中正确地看到结果,因为不涉及任何转换,并且SQL Developer呈现代码能够像预期的那样将两个代码组合成一个字符


由于“é”和“ó”都有Unicode和ISO 8859-1中提供的预组合表单,解决方法是向查询中添加组合函数。因此,如我之前所建议的,设置NLS_LANG,并向查询中添加围绕列的组合表达式。”

非常感谢,Keith

它对我来说工作正常。出于好奇,如果您删除
//translatit
,会发生什么?谢谢您的评论。如果我删除//TRANSLIT,我会在位置7处得到错误iconv:INLOCALL input sequence,它会在out.txt中的?Quie处停止。我做错了什么?我使用fedora13,当我键入locale时,它会显示LANG=en_US.utf8。谢谢。您遇到了什么错误?您确定输入文件是UTF-8编码的吗?
file input.txt
说什么?实际上,它是Oracle sqlplus的输出,与“export NLS_LANG=AMERICAN_AMERICA.AL32UTF8”一起批量运行。当我在sqlplus输出文件上执行file-bi时,它会显示charset=utf-8。因此,我使用utf-8作为iconv命令。iconv上没有AL32UTF8选项。你认为这就是原因吗?谢谢。基思,非常感谢你的回答。由于我不熟悉字符编码,我必须研究你的建议,看看是否能找到合适的解决方案。顺便问一下,是否可以使用sed或其他命令机械地将字符序列编码更改为另一种编码?谢谢。@user1026669:我毫不怀疑有一种方法可以使用组合字符自动将UTF-8转换为等效的UTF-8,而这种方法不能。(请注意,单个前缀字符上可以有多个组合字符,例如带有多个重音的
e
;这种转换无法处理这些情况)。我只是不知道怎么做。我相信其他人会的。非常感谢你,基思。我真的很感谢你的帮助。相关但可能不会立即有用:基思,你是对的。我从甲骨文社区找到了答案