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-ASCII 是UTF-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
iconv ,file may not report any change by the limited way in whichfile attempts 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.
我今天学到的一个教训是,我们不能相信
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.
我的文件是一个大的csv文件。
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行才会显示。我怀疑这就是
1 2 | $ pcregrep -no '[^\x00-\x7F]' source-file | head -n1 102321:? |
我在Mac上,所以使用PCRE的
我没有深入研究
不管我的文件编码是什么,这些非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 |
注意
让我们看看这些非ASCII字符是如何编码的。我将第一个非7位ASCII转储到
1 2 3 4 | $ pcregrep -o '[^\x00-\x7F]' source-file | head -n1 | hexdump -v -e '1/1"%02x "' d6 0a |
另一种方式。我知道第一个非7位ASCII字符在第102321行的位置85。我抓起那一行,告诉
1 2 3 | $ tail -n +102321 source-file | head -n1 | hexdump -C -s85 -n2 00000055 d6 4d |.M| 00000057 |
在这两种情况下,我们都看到特殊字符由
重要问题…我怎么知道这个角色是一个?不确定文件编码?答案是上下文。我打开文件,阅读文本,然后确定它应该是什么字符。如果我在
所以,我的文件似乎是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.
1 2 3 | $ tail -n +102321 output-file | head -n1 | hexdump -C -s85 -n2 00000055 c3 96 |..| 00000057 |
绝对是个变化。注意,我们有两个字节的非7位ASCII(用右边的"."表示),这两个字节的十六进制代码现在是
但是
我用
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,因为我们告诉
我再试一次,这次我用
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 |
繁荣!故事的寓意。不要相信
在处理大型文件时,一个可以解决
所以人们说你不能,我理解当你问一个问题并得到这样的答案时,你可能会感到沮丧。
如果您真的希望它以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编码了一个文件,并遇到了类似的问题。当我输入
为了解决这个问题,我输入:
除了其他人在这里提出的建议,我不知道如何确定编码。
您可以使用
一旦你得到了它,你可以做以下的事情:
1 | iconv -f old_format -t utf-8 input_file -o output_file |