文件中的奇怪字符

Pau*_*Ney 6 character-encoding unicode

我有一个 UTF-8 文件,其中包含一个奇怪的字符——对我来说就像

<96>
Run Code Online (Sandbox Code Playgroud)

这是它的显示方式 vi

vi 截图

以及它如何出现 gedit

gedit 截图

以及它在 LibreOffice 下的显示方式

LibreOffice 屏幕截图

这使得一系列基本的 Unix 工具行为不端,包括:

  1. cat file使角色消失,more以及
  2. 我无法在 vi/vim 中复制和粘贴——它甚至找不到自己
  3. grep 也无法显示任何内容,就好像该字符不存在一样。

该程序file运行良好并识别出一个 UTF-8 文件。我也知道,由于文件的性质,它很可能来自网络上的复制和粘贴,并且该字符最初代表 EMDASH。

我的基本问题是:

  1. 这个文件有什么问题吗?
  2. 如何在同一个文件中搜索它的其他出现?
  3. 如何 grep 其他可能包含相同问题/字符的文件?

该文件可以在这里找到:file.txt

Mic*_*mer 27

该文件包含 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 的一部分。

iconv -f utf-8 -t iso-8859-1 < mwe.txt | iconv -f cp1252 -t utf-8
Run Code Online (Sandbox Code Playgroud)

为我生成一个正确版本的最小示例。这件作品获UTF-8第一次转换为Latin-1的(反相早前误译),然后重新解释因为CP1252将其正确转换回UTF-8。

但是,它确实取决于实际文件中的其他内容。如果您在其他地方有 Latin-1 之外的字符,它将失败,因为它无法在第一步正确编码这些字符。

如果你没有 iconv,或者它对真实文件不起作用,你可以直接使用 sed 替换字节:

LC_ALL=C sed -e $'s/\xc2\x96/\xe2\x80\x93/g' < mwe.txt
Run Code Online (Sandbox Code Playgroud)

这将替换C2 96为 UTF-8 短划线编码E2 80 93。您也可以通过更改\xe2\x80\x93--.


您可以以类似的方式 grep。我们LC_ALL=C用来确保我们正在读取实际字节,而不是grep解释事物:

LC_ALL=C grep -R $'\xc2\x96` .
Run Code Online (Sandbox Code Playgroud)

将在此目录下的所有地方列出这些字节出现。如果您有混合内容,您可能希望将其限制为仅文本文件,因为二进制文件经常包含任何一对字节。

  • 是的,这是对一个不太有用的字符的完全正确的编码。 (2认同)