我试图识别在我正在使用的文件中发现的一个奇怪的字符:
$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353 \n
0000002
$ od -x file
0000000 0aeb
0000002
该文件使用 ISO-8859 编码,无法转换为 UTF-8:
$ iconv -f ISO-8859 -t UTF-8 file
iconv: conversion from `ISO-8859' is not supported
Try `iconv --help' or `iconv --usage' for more information.
$ iconv -t UTF-8 file
iconv: illegal input sequence at position 0
$ file file
file: ISO-8859 text
我的主要问题是如何解释od
这里的输出?我正在尝试使用这一页它让我可以在不同的字符表示之间进行翻译,但它告诉我,005353
作为“十六进制代码点”似乎卓
不正确,而0aeb
作为“十六进制代码点”૫
又似乎错误。
那么,我如何使用三个选项(355
、005353
或0aeb
)中的任何一个来找出它们应该代表什么字符?
是的,我确实尝试过使用 Unicode 工具,但它似乎也不是有效的 UTF 字符:
$ uniprops $(cat file)
U+FFFD ‹�› \N{REPLACEMENT CHARACTER}
\pS \p{So}
All Any Assigned Common Zyyy So S Gr_Base Grapheme_Base Graph X_POSIX_Graph
GrBase Other_Symbol Print X_POSIX_Print Symbol Specials Unicode
如果我理解 Unicode U+FFFD 字符的描述,它根本不是真正的字符,而是损坏字符的占位符。这是有道理的,因为该文件实际上不是 UTF-8 编码的。
答案1
您的文件包含两个字节,十六进制的 EB 和 0A。该文件可能使用每个字符一个字节的字符集,例如ISO-8859-1;在该字符集中,EB 是 ë:
$ printf "\353\n" | iconv -f ISO-8859-1
ë
其他候选者将是 δ代码页 437, Ù 在代码页 850...
od -x
在这种情况下,由于字节序的原因, 的输出会令人困惑;更好的选择是-t x1
使用单个字节:
$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002
od -x
映射到od -t x2
一次读取两个字节,并在小端系统上以相反的顺序输出字节。
当您遇到这样的文件时,它不是有效的 UTF-8(或者解释为 UTF-8 文件时没有任何意义),没有万无一失的方法来自动确定其编码(和字符集)。上下文可以提供帮助:如果它是过去几十年在西方 PC 上生成的文件,那么它很可能以 ISO-8859-1、-15(欧洲变体)或 Windows-1252 进行编码;如果比这个更老,CP-437 和 CP-850 可能是候选者。来自东欧系统、俄罗斯系统或亚洲系统的文件将使用我不太了解的不同字符集。然后是 EBCDIC...iconv -l
将列出所有已知的字符集iconv
,您可以从那里进行尝试和错误。
(有一次我把 CP-437 和 ATASCII 的大部分内容都背下来了,那是日子。)
答案2
请注意,这od
是缩写八进制转储,005353
两个字节作为八进制字,od -x
是0aeb
十六进制作为字,文件的实际内容是两个字节eb
和0a
十六进制,按这个顺序。
所以005353
和0aeb
不能仅仅被解释为“十六进制代码点”。
0a
是换行符 (LF),eb
取决于您的编码。file
只是猜测编码,它可以是任何东西。如果没有任何进一步的信息,文件来自何处等,将很难找到。
答案3
不可能 100% 准确地猜测文本文件的字符集。
类似的工具沙代,火狐浏览器,文件-i当没有定义明确的字符集信息时(例如,如果 HTML 在头部包含元 charset=... ,事情会更容易)将尝试使用启发式方法,如果文本足够大,那么启发式方法还不错。
下面,我将使用chardet
(pip install chardet
/apt-get install python-chardet
如有必要)演示字符集检测。
$ echo "in Noël" | iconv -f utf8 -t latin1 | chardet
<stdin>: windows-1252 with confidence 0.73
在获得良好的候选字符集后,我们可以使用iconv
或recode
类似的方法将文件字符集更改为“活动”字符集(在我的例子中为 utf-8),然后看看它是否猜测正确......
iconv -f windows-1252 -t utf-8 file
一些字符集(如 iso-8859-3、iso-8859-1)有许多共同的字符——有时很难看出我们是否找到了完美的字符集......
因此,拥有与相关文本(例如 XML)相关联的元数据非常重要。
答案4
#!/bin/bash
#
# Search in a file, a known (part of a ) String (i.E.: Begrüßung),
# by testing all encodings
#
[[ $# -ne 2 ]] && echo "Usage: encoding-finder.sh FILE fUnKy_CHAR_FOR_SURE_IN_FILE" && exit
FILE=$1
PATTERN=$2
for enc in $( iconv -l | sed 's/..$//')
do
iconv -f $enc -t UTF-8 $FILE 2>/dev/null | grep -m 1 $PATTERN && echo $enc
done
如果我得到一个文件,其中包含例如单词 Begrung,我可以推断可能意味着 Begrüßung。因此,我通过所有已知的编码对其进行转换,然后查看是否找到了正确转换的编码。
通常,有多种似乎合适的编码。
对于较长的文件,您可以剪切一个片段,而不是转换数百页。
所以我会称之为
encodingfinder.sh FILE Begrüßung
脚本测试是否通过使用已知编码进行转换,其中哪些会产生“Begrüßung”。
要找到这样的角色,少一点通常会有帮助,因为时髦的角色往往很引人注目。从上下文中,通常可以推断出要搜索的正确单词。但我们不想用十六进制编辑器检查这是什么字节,然后访问无尽的编码表,以找到我们的罪犯。 :)