当我使用iconv从UTF16转换为UTF8时,一切都很好但反之亦然。 我有这些文件:
a-16.strings: Little-endian UTF-16 Unicode c program text
a-8.strings: UTF-8 Unicode c program text, with very long lines
文本在编辑器中看起来没问题。当我运行时:
iconv -f UTF-8 -t UTF-16LE a-8.strings > b-16.strings
然后我得到了这个结果:
b-16.strings: data
a-16.strings: Little-endian UTF-16 Unicode c program text
a-8.strings: UTF-8 Unicode c program text, with very long lines
file
实用程序未显示预期的文件格式,并且文本在编辑器中看起来也不好。可能是iconv无法创建正确的BOM吗?我在MAC命令行上运行它。
为什么b-16不是正确的UTF-16LE格式?还有另一种方法可以将utf8转换为utf16吗?
下面会详细说明。
$ iconv -f UTF-8 -t UTF-16LE a-8.strings > b-16le-BAD-fromUTF8.strings
$ iconv -f UTF-8 -t UTF-16 a-8.strings > b-16be.strings
$ iconv -f UTF-16 -t UTF-16LE b-16be.strings > b-16le-BAD-fromUTF16BE.strings
$ file *s
a-16.strings: Little-endian UTF-16 Unicode c program text, with very long lines
a-8.strings: UTF-8 Unicode c program text, with very long lines
b-16be.strings: Big-endian UTF-16 Unicode c program text, with very long lines
b-16le-BAD-fromUTF16BE.strings: data
b-16le-BAD-fromUTF8.strings: data
$ od -c a-16.strings | head
0000000 377 376 / \0 * \0 \0 \f 001 E \0 S \0 K \0
$ od -c a-8.strings | head
0000000 / * * * Č ** E S K Y ( J V O
$ od -c b-16be.strings | head
0000000 376 377 \0 / \0 * \0 * \0 * \0 001 \f \0 E
$ od -c b-16le-BAD-fromUTF16BE.strings | head
0000000 / \0 * \0 * \0 * \0 \0 \f 001 E \0 S \0
$ od -c b-16le-BAD-fromUTF8.strings | head
0000000 / \0 * \0 * \0 * \0 \0 \f 001 E \0 S \0
很明显,每当我运行转换为UTF-16LE时,BOM都会丢失。 对此有何帮助?
答案 0 :(得分:35)
UTF-16LE
告诉iconv
生成小端UTF-16 而不用 BOM(字节顺序标记)。显然,它假设您指定了LE
,因此不需要BOM。
UTF-16
告诉它使用 BOM生成UTF-16文本(在本地机器的字节顺序中)。
如果您使用的是小端机器,我没有办法告诉iconv
使用BOM生成大端UTF-16,但我可能只是遗漏了一些东西。
我发现file
命令在没有BOM的情况下无法识别UTF-16文本,而您的编辑器可能也没有。但是如果你运行iconv -f UTF-16LE -t UTF_8 b-16 strings
,你应该得到原始文件的有效UTF-8版本。
尝试在文件上运行od -c
以查看其实际内容。
更新:
看起来你正在使用大端机器(x86是小端),并且你正在尝试生成带有BOM的小端UTF-16文件。那是对的吗?据我所知,iconv
不会直接这样做。但这应该有效:
( printf "\xff\xfe" ; iconv -f utf-8 -t utf-16le UTF-8-FILE ) > UTF-16-FILE
printf
的行为可能取决于您的区域设置;我有LANG=en_US.UTF-8
。
(任何人都可以提出更优雅的解决方案吗?)
另一种解决方法, if 你知道-t utf-16
产生的输出的字节顺序:
iconv -f utf-8 -t utf-16 UTF-8-FILE | dd conv=swab 2>/dev/null
答案 1 :(得分:3)
我首先转换为UTF-16
,如有必要,它会在字节顺序前加上as Keith Thompson mentions。然后由于UTF-16
没有定义字节序,我们必须使用file
来确定它是UTF-16BE
还是UTF-16LE
。最后,我们可以转换为UTF-16LE
。
iconv -f utf-8 -t utf-16 UTF-8-FILE > UTF-16-UNKNOWN-ENDIANNESS-FILE
FILE_ENCODING="$( file --brief --mime-encoding UTF-16-UNKNOWN-ENDIANNESS-FILE )"
iconv -f "$FILE_ENCODING" -t UTF-16LE UTF-16-UNKNOWN-ENDIANNESS-FILE > UTF-16-FILE
答案 2 :(得分:0)
这可能不是一个优雅的解决方案,但我找到了一种手动方式来确保我的问题的正确转换,我认为这与此主题的主题类似。
问题:
我从用户那里获得了一个文本数据文件,我将使用shell脚本(标记化,拆分等)在Linux(特别是Ubuntu)上处理它。我们调用文件myfile.txt
。我得到的东西是不对的第一个迹象是令牌化不起作用。因此,当我在file
上运行myfile.txt
命令并获得以下
$ file myfile.txt
myfile.txt: Little-endian UTF-16 Unicode text, with very long lines, with CRLF line terminators
如果文件符合要求,那么本来应该是对话:
$ file myfile.txt
myfile.txt: ASCII text, with very long lines
解决方案: 为了使数据文件兼容,下面是我发现在经过一些试验和其他步骤的错误后工作的3个手动步骤。
首先通过vi
(或vim
)以相同的编码转换为Big Endian。 vi myfile.txt
。在vi
执行:set fileencoding=UTF-16BE
然后写出文件。您可能必须使用:!wq
vi myfile.txt
(现在应该是utf-16BE)。在vi
执行:set fileencoding=ASCII
然后写出文件。同样,您可能必须使用!wq
强制写入。
运行dos2unix
转换器:d2u myfile.txt
。如果你现在运行file myfile.txt
,你现在应该看到一个输出或更熟悉的东西,并确保如下:
myfile.txt: ASCII text, with very long lines
就是这样。这对我有用,然后我就可以运行myfile.txt
的处理bash shell脚本了。我发现我不能跳过第2步。也就是说,在这种情况下,我不能直接跳到第3步。希望你能发现这个信息有用;希望有人可以通过sed
等自动化它。欢呼声。