我有一个 UTF-8 文件,其中包含一个奇怪的字符——对我来说就像
<96>
这就是它的显示方式vi
以及它是如何出现的gedit
以及它在 LibreOffice 下的显示方式
这使得一系列基本的 Unix 工具行为不端,包括:
cat file
使角色消失,more
以及- 我无法在 vi/vim 中复制和粘贴——它甚至找不到自己
grep
也无法显示任何内容,就好像该角色不存在一样。
该程序file
运行良好,并将其识别为 UTF-8 文件。我也知道,由于文件的性质,它很可能来自网络上的复制和粘贴,并且该字符最初代表 EMDASH。
我的基本问题是:
- 这个文件有什么问题吗?
- 如何在同一文件中搜索它的其他出现?
- 如何查找可能包含相同问题/字符的其他文件?
该文件可以在这里找到:file.txt
该文件包含 bytes
C2 96
,它们是代码点 U+0096 的UTF-8编码。该代码点是C1 控制字符之一,通常称为 SPA“保护区域开始”(或“保护区域”)。这对于任何现代系统都不是一个有用的字符,但它的存在不太可能有害。其原始来源可能是某个单字节 8 位编码中的字节 0x96,该字节在途中某处被错误地转码。可能这最初是一个Windows CP1252破折号“-”,在该编码中具有字节值 96 - 大多数其他可能的候选者在位置 80-9F 上都有控制集 - 已被翻译为 UTF-8,就好像它是拉丁语一样 - 1 ( ISO/IEC 8859-1 ),这并不罕见。如您所见,这将导致字节被解释为控制字符并相应地进行翻译。
您可以使用该工具修复此文件,该
iconv
工具是 glibc 的一部分。为我生成您的最小示例的正确版本。其工作原理是首先将 UTF-8 转换为 latin-1(反转之前的误译),然后将其重新解释为cp1252 以正确地将其转换回 UTF-8。
但是,它确实取决于真实文件中的其他内容。如果您在其他地方有 Latin-1 之外的字符,它将失败,因为它无法在第一步正确编码这些字符。
如果你没有 iconv,或者它对真实文件不起作用,你可以直接使用 sed 替换字节:
这将替换
C2 96
为 UTF-8 破折号编码E2 80 93
。您也可以通过将其更改\xe2\x80\x93
为--
.你可以用类似的方式 grep。我们
LC_ALL=C
用来确保我们正在读取实际字节,而不是grep
解释:将在此目录下的所有位置列出这些字节出现。如果您有混合内容,您可能希望将其限制为仅文本文件,因为二进制文件将相当频繁地包含任何字节对。
0x96 是 Windows 代码页 1252 中的短划线。
c2
它前面的字节似乎是双角字符中的默认第一个字节。其他人可以更准确地解释它。要搜索其他匹配项,请在命令模式下将光标放在它上面,点击
yl
(拉出一个字符),然后键入/<Ctrl>+r"
。(ctrl+r 允许您将寄存器的内容插入到命令中,并且该"
寄存器是最后被拉出的任何内容)。如果您希望它在终端中呈现,只需将其替换为两个连字符即可。如果那是您拥有的 bibtex 文件,那么两个连字符是键入它的适当方式。
为了展示如何找到该字符的出现,您可以通过 hexdump 工具(如
xxd
.文件中的文本是
pages = {1113},
,是的,它看起来像数字1113
,但实际上在第一个之后有一个不同的字符1
。而且,是的,您可以从该网页的编辑链接复制粘贴字符串以获取编码字符。我们可以使用一些工具查看字符串内部:
或者,为了明确并允许在不使用编辑页面的情况下轻松复制粘贴:
因此,字符是两个字节值
c2 96
(十六进制)或302 226
(八进制)。它可能是字节值的 UTF-8 编码
96
,或者表示为 Unicode 字符:U-0096
.该值在目前的 UTF-8 或更好的 ISO-8859-1 中是控制字符(维基百科页面)和(Unicode PDF)的 C1 区域中的控制字符,十进制从 128 到 159。具体来说,U-0096 被称为“START OF GUARDED AREA”或SPA。
该值(dec 150)超出了 ASCII 范围(0-127)并且(在过去)用于表示几个字符,具体取决于所使用的代码页。假设它以前是一个破折号(标记范围 1-113),在 Windows-1252(Microsoft 页面)(维基百科 1252)中编码并称为破折号(这是两个破折号en和em)(维基百科的破折号)或简单地说,用外行的话来说,破折号(
-
)。Q1:这个文件有什么问题吗?
并非如此,控制字符是有效字符,很少使用但仍然有效。
但是您可以用破折号替换它们以使编辑更容易。
Q2 - 我如何在同一个文件中搜索它的其他出现?
或者,grep 可以搜索字符(颜色突出显示将不可见,因为字符不可打印)并打印该行。
或更广泛地说,查找该控制字符范围内的所有字符并列出包含此类字符的文件:
Q3 - 我如何 grep 查找可能包含相同问题/字符的其他文件?
这将列出 (
-l
) 匹配该字符的文件。