关于utf 8:强制编码从US-ASCII到UTF-8(iconv)

Force encode from US-ASCII to UTF-8 (iconv)

我正在尝试将一系列文件从US-ASCII转换为UTF-8。

为此,我正在使用ICONV:

1
iconv -f US-ASCII -t UTF-8 file.php > file-utf8.php

事情是我的原始文件是US-ASCII编码的,这使得转换不会发生。很明显,这是因为ASCII是UTF-8的一个子集…

http://www.linux questions.org/questions/linux-software-2/iconv-us-ascii-to-utf-8-or-iso-8859-15-a-705054/

引文:

There's no need for the textfile to appear otherwise until non-ascii
characters are introduced

真的。如果我在文件中引入一个非ASCII字符并保存它,比如说使用Eclipse,文件编码(charset)将切换到UTF-8。

在我的例子中,我希望无论如何强制ICONV将文件转换为UTF-8。是否包含非ASCII字符。

注意:原因是我的php代码(非ascii文件…)正在处理一些非ascii字符串,这会导致字符串无法很好地解释(法语):

Il ??tait une fois... l'homme s??rie anim??e mythique d'Albert

Barill?? (Procidis), 1?¨re

...

编辑

  • US-ASCIIUTF-8的一个子集(见下面的内德回答)
  • 也就是说,US-ASCII文件实际上是在UTF-8中编码的。
  • 我的问题来自其他地方


ascii是utf-8的一个子集,所以所有的ascii文件都已经是utf-8编码的。ASCII文件中的字节和"编码为UTF-8"产生的字节将完全相同。他们之间没有区别,所以没必要做任何事。

看起来您的问题是文件实际上不是ASCII。您需要确定它们使用的是什么编码,并正确地对它们进行转码。


短答案

  • 只有在文件编码中的警告可能是错误的(特别是在特殊字符只出现在大型文件后面的情况下)。
  • 您可以使用hexdump来查看非7-BIT-ASCII文本的Bytes,并比较非7-BIT-ASCII文本的Code Tables for Common Ecodings(ISO-8859-*,UTF-8)来决定什么是编码。
  • 输入/输出将使用什么样的输入/输出编码,具体参照文件内容。如果你具体说明输入错误编码输出将被填充。
  • Even after running iconvfilemay not report any change by the limited way in which fileattempts to guess at the encoding.作为一个具体的例子,见我的长篇答案。
  • 7-bit ASCII(AKA US-ASCII)is identical at a byte level to UTF-8 and the 8-bit ASCII extensions(ISO-8859-*).如果你的文件只有7位字符,那么你可以叫它UTF-8,ISO-8859-*或美国信息交换标准码,因为它们是完全相同的。只有在您的文件在ASCII范围外具有特征的情况下,才会有意义地谈论UTF-8和其他编码。

长答案

今天我来到你的问题上。也许我可以添加更多的信息,帮助其他人逃进这个问题。

okay.

首先,美国信息交换标准码过载,导致混乱。

okay.

7-BIT ASCII only includes 128 characters(00-7F or 0-127 in decimal).美国信息交换标准码是美国信息交换标准码。

okay.

HTTPS://en.wikipedia.org/wiki/asci

okay.

UTF-8对其第一128个字符使用相同的编码作为7位ASCII。So a text file that only contains characters from that range of the first 128 characters will be identical at a byte level whether coded with UTF-8 or 7-bit ASCII.

okay.

HTTPS://en.wikipedia.org/wiki/UTF-8 355;codepage layout

okay.

The term extended ascii (or high ascii) refers to eight-bit or larger character encodings that include the standard seven-bit ASCII characters, plus additional characters.

Ok.

https://en.wikipedia.org/wiki/extended asci

okay.

ISO-8859-1(ISO"ISO Latin 1")是一个特殊的8-bit ASCII扩展标准,它是西欧COVERS最主要的特征。东欧语言和西里尔语言还有其他国际标准化组织标准。ISO-8859-1包括类似的字符吗?的然后呢?"为了德国和西班牙"Extension"means that ISO-8859-1 includes the 7-bit ASCII standard and adds characters to it by using the 8th bit.因此,对于第一个128个字符,它等于一个字节级的ASCII和UTF-8编码文件。然而,当你开始处理第一个128之外的特征时,你的UTF-8在字节级不等效,如果你想要你的"扩展ASCII"文件,就必须转换成UTF-8编码。

okay.

HTTPS://en.wikipedia.org/wiki/extended 350;ISO 8859 uu and proprietary uu adaptations

okay.

我今天学到的一个教训是,我们不能相信file总是正确地解释文件的字符编码。好的。

https://en.wikipedia.org/wiki/file_28command%29好的。

The command tells only what the file looks like, not what it is (in the case where file looks at the content). It is easy to fool the program by putting a magic number into a file the content of which does not match it. Thus the command is not usable as a security tool other than in specific situations.

Ok.

file在文件中查找提示类型的幻数,但这些数字可能是错误的,不能保证正确性。file还试图通过查看文件中的字节来猜测字符编码。基本上,file有一系列测试,帮助它猜测文件类型和编码。好的。

我的文件是一个大的csv文件。file将此文件报告为US ASCII编码,这是错误的。好的。

1
2
3
4
5
6
7
$ ls -lh
total 850832
-rw-r--r--  1 mattp  staff   415M Mar 14 16:38 source-file
$ file -b --mime-type source-file
text/plain
$ file -b --mime-encoding source-file
us-ascii

我的文件中有umlauts(即?).第一个非7位ASCII直到文件中超过100K行才会显示。我怀疑这就是file没有意识到文件编码不是US-ASCII的原因。好的。

1
2
$ pcregrep -no '[^\x00-\x7F]' source-file | head -n1
102321:?

我在Mac上,所以使用PCRE的grep。有了GNUgrep,您可以使用-P选项。或者,在Mac上,可以安装coreutils(通过自制或其他方式),以获得gnu grep。好的。

我没有深入研究file的源代码,手册页也没有详细讨论文本编码检测,但我猜file在猜测编码之前没有查看整个文件。好的。

不管我的文件编码是什么,这些非7位的ASCII字符都会破坏一切。我的德语csv文件是;,分离和提取单个列不起作用。好的。

1
2
3
4
5
6
$ cut -d";" -f1 source-file > tmp
cut: stdin: Illegal byte sequence
$ wc -l *
 3081673 source-file
  102320 tmp
 3183993 total

注意cut错误,我的"tmp"文件只有102320行,第102321行有第一个特殊字符。好的。

让我们看看这些非ASCII字符是如何编码的。我将第一个非7位ASCII转储到hexdump中,做一些格式化,删除换行符(0a并只取前几个。好的。

1
2
3
4
$ pcregrep -o '[^\x00-\x7F]' source-file | head -n1 | hexdump -v -e '1/1"%02x
"'
d6
0a

另一种方式。我知道第一个非7位ASCII字符在第102321行的位置85。我抓起那一行,告诉hexdump从位置85开始取两个字节。您可以看到由"."表示的特殊(非7位ASCII)字符,下一个字节是"m"…所以这是单字节字符编码。好的。

1
2
3
$ tail -n +102321 source-file | head -n1 | hexdump -C -s85 -n2
00000055  d6 4d                                             |.M|
00000057

在这两种情况下,我们都看到特殊字符由d6表示。因为这个角色是一个?这是一封德文信,我猜ISO-8859-1应该包括这封信。当然,你可以看到"d6"是匹配的(https://en.wikipedia.org/wiki/iso/iec_-1 codepage_layout)。好的。

重要问题…我怎么知道这个角色是一个?不确定文件编码?答案是上下文。我打开文件,阅读文本,然后确定它应该是什么字符。如果我在vim中打开它,它显示为?因为vimfile更好地猜测字符编码(在本例中)。好的。

所以,我的文件似乎是ISO-8859-1。理论上,我应该检查其他非7位ASCII字符,以确保ISO-8859-1是一个很好的适合…没有什么能强迫程序在将文件写入磁盘时只使用单一编码(除了礼貌之外)。好的。

我将跳过支票,转到转换步骤。好的。

1
2
3
$ iconv -f iso-8859-1 -t utf8 source-file > output-file
$ file -b --mime-encoding output-file
us-ascii

hmm.file仍然告诉我这个文件是US-ASCII,即使在转换之后。我们再和hexdump核对一下。好的。

1
2
3
$ tail -n +102321 output-file | head -n1 | hexdump -C -s85 -n2
00000055  c3 96                                             |..|
00000057

绝对是个变化。注意,我们有两个字节的非7位ASCII(用右边的"."表示),这两个字节的十六进制代码现在是c3 96。如果我们看一下,我们现在似乎有UTF-8(c3 96是正确的编码方式吗?采用UTF-8)http://www.utf8-chartable.de/好的。

但是file仍然报告我们的文件是us-ascii吗?好吧,我认为这可以追溯到file不查看整个文件的问题,而且第一个非7位ASCII字符直到深入到文件中才出现。好的。

我用sed来粘A?在文件的开头,看看会发生什么。好的。

1
2
3
4
5
6
7
$ sed '1s/^/?\'$'
/' source-file > test-file
$ head -n1 test-file
?
$ head -n1 test-file | hexdump -C
00000000  c3 96 0a                                          |...|
00000003

酷,我们有一个巫术。注意编码是c3 96(utf-8)。隐马尔可夫模型。好的。

再次检查同一文件中的其他umlaut:好的。

1
2
3
$ tail -n +102322 test-file | head -n1 | hexdump -C -s85 -n2
00000055  d6 4d                                             |.M|
00000057

ISO-859-1哎呀!只是为了说明把编码搞砸是多么容易。好的。

让我们尝试用前面的umlaut转换新的测试文件,看看会发生什么。好的。

1
2
3
4
5
6
7
$ iconv -f iso-8859-1 -t utf8 test-file > test-file-converted
$ head -n1 test-file-converted | hexdump -C
00000000  c3 83 c2 96 0a                                    |.....|
00000005
$ tail -n +102322 test-file-converted | head -n1 | hexdump -C -s85 -n2
00000055  c3 96                                             |..|
00000057

哎呀。第一个是utf-8的umlaut被解释为iso-8859-1,因为我们告诉iconv。第二个umlaut从d6正确转换为c3 96。好的。

我再试一次,这次我用vim来做?插入而不是插入sedvim似乎更好地检测到编码(如"latin1"又称为iso-8859-1),所以它可能会插入新的?具有一致的编码。好的。

1
2
3
4
5
6
7
8
9
$ vim source-file
$ head -n1 test-file-2
?
$ head -n1 test-file-2 | hexdump -C
00000000  d6 0d 0a                                          |...|
00000003
$ tail -n +102322 test-file-2 | head -n1 | hexdump -C -s85 -n2
00000055  d6 4d                                             |.M|
00000057

看起来不错。新的和旧的umlauts看起来像ISO-8859-1。好的。

现在进行测试。好的。

1
2
3
4
5
$ file -b --mime-encoding test-file-2
iso-8859-1
$ iconv -f iso-8859-1 -t utf8 test-file-2 > test-file-2-converted
$ file -b --mime-encoding test-file-2-converted
utf-8

繁荣!故事的寓意。不要相信file总是猜测你的编码是正确的。在同一个文件中易于混合编码。当有疑问的时候,看看这个六角形。好的。

在处理大型文件时,一个可以解决file这种特定限制的黑客(也容易失败)是缩短文件,以确保特殊字符出现在文件的早期,因此file更容易找到它们。好的。字母名称Update(P)Christos Zoula Updated EDOCX1为确保字节可配置性而拼出0一天转一圈,在美丽的要求,AWESOME!好的,好的。(P)http://bugs.gw.com/view.php?ID=533http://github.com/file/file/commit/d04de269e0b060ccd0a7d1bf4974fed1d75be7d9e好的,好的。(P)The Feature was released in EDOCX1 English 0 version 5.26.好的,好的。(P)在确定占用时间的人选之前,先看一看一大份文件。然而,这是一个很好的选择,可供具体使用——在最好的情况下,可增加时间/时间。好的,好的。(P)3.Use the following option:好的,好的。字母名称(P)Something like…好的,好的。字母名称(P)…如果你想要一支独立自主的力量,那么你就应该继续下去Of course this only works if you have EDOCX1 penography 0 5.26 or newer.好的,好的。(P)I haven't built/tested the latest releases yet.我最喜欢的机器现在已经有了0-5.04(2010)希望有一天这一释放将使这一点从上流下来。好的,好的。好吧。


所以人们说你不能,我理解当你问一个问题并得到这样的答案时,你可能会感到沮丧。

如果您真的希望它以UTF-8而不是US ASCII显示,那么您需要分两步来完成它。

第一:

1
iconv -f us-ascii -t utf-16 yourfile > youfileinutf16.*

第二:

1
iconv -f utf-16le -t utf-8 yourfileinutf16 > yourfileinutf8.*

如果你做一个文件-我你会看到新的字符集是utf-8。

希望它有帮助。


我认为Ned有问题的核心——你的文件实际上不是ASCII。尝试

1
iconv -f ISO-8859-1 -t UTF-8 file.php > file-utf8.php

我猜你实际上使用的是ISO-8859-1,它在大多数欧洲语言中都很流行。


下面是一个脚本,它将查找所有与您传递的模式匹配的文件,然后将它们从当前的文件编码转换为UTF-8。如果编码是US ASCII,那么它仍然显示为US ASCII,因为这是UTF-8的一个子集。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env bash    
find . -name"${1}" |
    while read line;
    do
        echo"***************************"
        echo"Converting ${line}"

        encoding=$(file -b --mime-encoding ${line})
        echo"Found Encoding: ${encoding}"

        iconv -f"${encoding}" -t"utf-8" ${line} -o ${line}.tmp
        mv ${line}.tmp ${line}
    done

US-ASCII和UTF-8没有区别,所以不需要重新转换它。但这里有一点提示,如果您在重新编码时遇到特殊字符的问题。

在source charset参数后添加//translit。

例子:

1
iconv -f ISO-8859-1//TRANSLIT -t UTF-8 filename.sql > utf8-filename.sql

这有助于我处理奇怪的引用类型,这些引用完全打破了字符集重新编码过程。


我不小心用UTF-7编码了一个文件,并遇到了类似的问题。当我输入file -i name.file时,我会得到charset=us-asciiiconv -f us-ascii -t utf-9//translit name.file不起作用,因为我收集了utf-7是美国ASCII的一个子集,就像utf-8一样。

为了解决这个问题,我输入:iconv -f UTF-7 -t UTF-8//TRANSLIT name.file -o output.file

除了其他人在这里提出的建议,我不知道如何确定编码。


您可以使用file -i file_name检查原始文件格式。

一旦你得到了它,你可以做以下的事情:

1
iconv -f old_format -t utf-8 input_file -o output_file