使用iconv将UTF8转换为UTF16

时间:2012-01-19 09:43:37

标签: linux macos unicode command-line

当我使用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都会丢失。 对此有何帮助?

3 个答案:

答案 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个手动步骤。

  1. 首先通过vi(或vim)以相同的编码转换为Big Endian。 vi myfile.txt。在vi执行:set fileencoding=UTF-16BE然后写出文件。您可能必须使用:!wq

  2. 强制执行此操作
  3. vi myfile.txt(现在应该是utf-16BE)。在vi执行:set fileencoding=ASCII然后写出文件。同样,您可能必须使用!wq强制写入。

  4. 运行dos2unix转换器:d2u myfile.txt。如果你现在运行file myfile.txt,你现在应该看到一个输出或更熟悉的东西,并确保如下:

    myfile.txt: ASCII text, with very long lines
    
  5. 就是这样。这对我有用,然后我就可以运行myfile.txt的处理bash shell脚本了。我发现我不能跳过第2步。也就是说,在这种情况下,我不能直接跳到第3步。希望你能发现这个信息有用;希望有人可以通过sed等自动化它。欢呼声。