【问题标题】:Special character '\u0098' read as '\u02dc' using charCodeAt()使用 charCodeAt() 将特殊字符 '\u0098' 读取为 '\u02dc'
【发布时间】:2012-04-22 06:18:13
【问题描述】:

我正在从 Java 创建 test.js,如下所示。 Test.js 实现了函数 d(),接收作为参数的特殊字符 ∼ ('\u0098');

函数 d() 应该显示此特殊字符的 charCodeAt(),即 152。但是,它显示 732。

请注意,字符 152 和 732 都由特殊字符 ~ 表示,如下所示。

http://www.fileformat.info/info/unicode/char/098/index.htm

http://www.fileformat.info/info/unicode/char/2dc/index.htm

如何强制函数 d() 显示 152 而不是 732? (字符集问题?)。谢谢

TEST.JAVA

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
    res.setHeader("Content-Type", "text/javascript;charset=ISO-8859-1");
    res.setHeader("Content-Disposition","attachment;filename=test.js");
    res.setCharacterEncoding("ISO-8859-1");
    PrintWriter printer=res.getWriter();
    printer.write("function d(a){a=(a+\"\").split(\"\");alert(a[0].charCodeAt(0));};d(\""); // Writes beginning of d() function
    printer.write('\u0098'); // Writes special character as parameter of d()
    printer.write("\");"); // Writes end of d() function
    printer.close();
}

由 TEST.JAVA 创建的 TEST.JS

function d(a)
{
  a=(a+"").split("");
  alert(a[0].charCodeAt(0));
};
d("˜"); // Note special character representing '\u0098'

TEST.HTML

<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>
<body>
<script type="text/javascript" charset="ISO-8859-1" src="test.js"></script>
</body>
</html>

【问题讨论】:

标签: javascript servlets unicode character-encoding iso-8859-1


【解决方案1】:

请注意,字符 152 和 732 都由特殊字符 ~ 表示,如下所示。

不是真的。 ˜ 是明确的字符 U+02DC (732),所以 charCodeAt 正在做正确的事情。字符 U+0098 (152) 是一个几乎从不使用的隐形控制代码。

诀窍在于"ISO-8859-1" 对于 Java 和 Web 浏览器具有不同的含义。对于 Java,它确实是 ISO-8859-1 标准,它精确映射到 Unicode 的前 256 个代码点。其中包括 128-159 处的一系列很少使用的 C1 控制字符。

但是对于网络浏览器,"ISO-8859-1" 实际上是指 Windows 代码页 1252(西欧),一种将各种有用字符放在 128–159 块中的编码。这种行为源于早期的仅使用机器默认代码页的 Web 浏览器。为浏览器添加适当的 Unicode 和编码支持后,兼容性问题要求继续支持 Windows 字符,尽管它们被错误地标记为 ISO-8859 格式。

因此,当您在 ISO-8859-1 中从 Java 写入 U+0098 字符时,您会得到一个 0x98 字节,然后浏览器会将其读取为 U+02DC。这通常是无害的,因为实际上没有人想要使用 U+0080–U+009F 范围内的 C1 控制代码。但这肯定令人困惑。

这个古老的怪癖,以及将 128-159 范围内的 &amp;#...; 字符引用视为 cp1252 字节的相关问题,最终被记录并标准化为 HTML5 的一部分,但仅适用于 HTML 解析规则。 (不是 XHTML5,因为它遵循更合理的 XML 规则。)这就是为什么引用的 fileformat.info 页面似乎误导性地说,U+0098 呈现为 ˜

如果您真的需要提取字符的 cp1252 字节数,则必须使用查找表来帮助您,因为 JavaScript 看不到该信息。例如:

var CP1252EXTRAS= '\u20ac\u20ac\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\u0152\u017d\u017d\u017d\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\u0153\u017e\u0178';

function getCodePage1252Byte(s) {
    var ix= CP1252EXTRAS.indexOf(s);
    if (ix!==-1)
        return 128+ix;
    var c= s.charCodeAt(0);
    if (c<128 || c>=160 && c<256)
        return c;
    return -1;
}

您可能不想这样做。无论如何,通常答案不是使用 ISO-8859-1,而是坚持使用良好的旧 UTF-8(The Only Sensible Encoding™)。

无论如何,&lt;script charset="..."&gt; 并不是每个浏览器都支持,Content-Type: text/javascript;charset=... 也不是每个浏览器都支持。没有可靠的方法以不同的编码为包含页面提供 JavaScript。如果您不是 100% 每个包含页面都将使用与脚本相同的编码,那么唯一安全的方法是保持 JavaScript ASCII 安全,输出 JavaScript \unnnn 序列而不是文字字节。

(兼容 ASCII 的 JSON 编码器可能会帮助您做到这一点。)

【讨论】:

    【解决方案2】:

    试试:

        printer.write('\\u0098');
    

    JavaScript 也可以理解 \uNNNN,因此您可以使用所需的字符代码显式地形成字符串。

    【讨论】:

    • 使用 \\.但是我需要这是一个单个字符而不是整个 \u0098 字符串。谢谢
    • 为什么是双“\”?而 Arturo,这是一个单一的字符,转义工作就像在 C/C++ 中一样。试试'\u0098'.charCodeAt(0)。它返回 152。
    • @Imp 双反斜杠是为了让 `\` 字符“存活”到 JavaScript 源代码中。
    • @Arturo 不,如果处理得当,应该不会在 JavaScript 中导致错误。关键是,如果您生成的 JavaScript 代码明确涉及数字转义序列 \u0098,那么您将强制解释器使用该字符代码构建字符串。
    • @Pointy 啊,没注意到你是用Java输出的,不是用JS代码手动写的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多