我有一个包含 EM Dash(或—
HTML)的 ASCII 文件。十六进制值为 0x97。当我们通过一个应用程序传递这个文件时,它以 UTF-8 格式到达,并将字符转换为—
HTML 格式的 0xC297。但是,当我们通过不同的应用程序传递这个文件时,它会将字符转换为 0xE28094 或—
.
什么会导致这些应用程序以不同方式转换这些字符?它可能是代码页设置吗?
是错的。当您使用数字字符引用时,数字指的是 Unicode 代码点。对于低于 256 的数字,与 ISO-8859-1 中的代码点相同。在 8859-1 中,字符 151 属于“C1 控制代码”,而不是破折号或任何其他可见字符。
由于字符 151 是 Windows 代码页 1252(西欧)中的破折号,因此出现了混淆。很多人认为 cp1252 和 ISO-8859-1 是一回事,但实际上并非如此:C1 范围内(128 到 159)的字符是不同的。
第一个应用程序将您的“ASCII”文件* 读取为 ISO-8859-1,但实际上它可能是 cp1252,您需要一种方法来提示应用程序它所期望的编码。
(*:如果文件中有最高位设置的字符,则“ASCII”是用词不当。您可能是指“ANSI”,这实际上也是用词不当,但在 Windows 世界中一直停留在“文本编码”的意思在当前系统默认代码页中”。)
—
不是 em dash,您的文本被错误地从 em dash 翻译为该值。—
是破折号的 HTML 十进制实体。具体来说,它引用了代表 em dash 的 Unicode 代码点 8212。您的第一个应用程序...
数据以 w-1252 编码的破折号开始。在 w-1252 中,短划线映射到十进制值 151(十六进制的 0x97,或二进制的 10010111)。
在某些时候,破折号由认为文件中的字节是 iso-8859-1 编码文本的代码处理。当该代码将 0x97 解释为字符串/字符时,它根据 iso-8859-1 编码将 0x97 映射到字符。在 iso-8859-1 中,0x97 映射到字符“保护区域结束”。
接下来,代码认为是“保护区域结束”控制字符的字符串被编码为 utf-8。以 utf-8 编码的“保护区结束”是两字节序列: 0xC2 0x97。
您的第二个应用程序...
文本文件被正确解释为 w-1252,因此 0x97 被识别为 em dash,在 utf-8 中正确编码为 em dash: 0xE2 0x80 0x94。
是什么影响了这种行为 在人们将数据输入表单的 Web 应用程序中,我们有相同的 0x97->0xC297 场景。我发现网页的字符集被声明为 iso8859-1,而浏览器处理 w1252 字符的最佳方法是将它们作为 iso 字节发送而不提醒用户或服务器。服务端收到数据认为是iso,转成utf-8,产生0xC297。
基本上任何时候应用程序接触文本时都需要告诉它文本是如何编码的,否则它可能会退回到系统默认值。如果发生这种情况,您将面临数据损坏的风险。
ASCII 文件不能包含字符 0x97,因为 ASCII 字符集的范围仅从 0x00 到 0x7F。因此,您的文件不是 ASCII,而是其他一些单字节编码。例如 windows-1250 编码在 0x97 处有 em-dash。
如果应用程序使用其他编码而不是用于创建文件的编码对文本文件进行解码,则任何高于 0x7F 的字符都是错误的。
在 unicode 中,破折号的字符代码为 0x2014,或十进制的 8212。
例如,在使用 windows-1250 作为编码的网页中,代码—
将呈现为 em-dash:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>em-dash</title>
<meta http-equiv="content-type" content="text/html; charset=windows-1250"/>
</head>
<body>
<div>—</div>
</body>
</html>