1

从 JSON 2.xx 开始,我需要设置latin1标志以使变音符号对 html 文档安全:

my $obj_with_umlauts = {
    title  => 'geändert',
}


my $json = JSON->new()->latin1(1)->encode($obj_with_umlauts);

使用 JSON 1.xx 不需要这样做:

my $json = JSON->new()->objToJson($obj_with_umlauts);

html 文档位于 iso-8559-1(元标记)中。

谁能向我解释为什么?

4

2 回答 2

6

这是一个巨大的蠕虫罐头,你要在这里打开。

我怀疑答案类似于“在 JSON.pm 的字符处理中修复了一个错误”。但是如果没有更多关于您的情况的信息,很难知道发生了什么。

是如何$string_with_umlauts设置的?您如何对写入 HTML 文档的数据进行编码?

您想正确处理 utf8 数据(您真的应该),还是假设您生活在 Latin1 世界中,您是否很高兴?

重要的是要意识到,如果您完全忽略 Unicode 考虑因素,那么您的程序通常看起来工作正常,因为错误通常会相互抵消。当您开始解决 Unicode 问题时,在您解决所有问题之前,您的程序似乎变得越来越糟。

Perl Unicode 教程是开始学习这些东西的好地方。

PS 这是“Perl”,而不是“PERL”。

于 2013-06-05T12:52:34.750 回答
4

你在说什么?

$ perl -MJSON -E'
   say $JSON::VERSION;
   my $json = JSON->new()->objToJson(["\xE4"]);
   say sprintf "%v02X", $json;
'
1.15
5B.22.E4.22.5D         # Unicode code points for ["ä"]

$ perl -MJSON -E'
   say $JSON::VERSION;
   my $json = JSON->new()->encode(["\xE4"]);
   say sprintf "%v02X", $json;
'
2.59
5B.22.E4.22.5D         # Unicode code points for ["ä"]

这两个字符串是相同的!事实上,添加->latin1()不会改变任何东西,因为 Unicode 代码点 U+00E4 的 iso-8859-1 编码是 E4。

$ perl -MJSON -E'
   say $JSON::VERSION;
   my $json = JSON->new()->latin1()->encode(["\xE4"]);
   say sprintf "%v02X", $json;
'
2.59
5B.22.E4.22.5D         # iso-8859-1 encoding of ["ä"]

后两者之间有一个区别:它在标量中的存储方式不同。那应该完全没有区别。如果代码以不同的方式对待它们,则该代码错误地读取了标量中的数据,并且代码存在错误。


$string_with_umlauts 绝对是 winLatin 中的一个字符串

嗯,这是第一个错误。

JSON 需要解码文本字符串(Unicode 代码点字符串),而不是编码文本。

也就是说,使用 iso-8859-1 编码的字符串和 Unicode 代码点字符串之间恰好没有区别。例如,当使用 iso-8859-1 编码时,“ä”是字节 E4,它是 Unicode 代码点 U+00E4,相同数字的两种不同表示法。

但是,如果字符串是使用 cp1252 编码的,那么字符 €‚ƒ„…†‡ˆ‰Š‹ŒŽ''“”•--∼™š›œžŸ (cp1252 中的字符但 iso 中没有-8859-1)。例如,当使用 cp1252 编码时,“€”是字节 80,但它是 Unicode 代码点 U+20AC。0x80 != 0x20AC。

html 文档位于 iso-8559-1(元标记)中。

然后在某些时候,您必须将输出编码为 iso-8859-1。您可以使用:encoding层,或使用编码encode或使用 JSON 的->latin1指令来完成。使用此最终选项的优点是,它将导致 JSON 在尝试对其进行编码之前转义 iso-8859-1 字符集之外的任何字符。

谁能向我解释为什么?

您有一个代码(一个 XS 模块),它读取标量的底层字符串缓冲区并将其错误地视为字符串的内容。该模块中有一个错误。

于 2013-06-05T14:29:24.257 回答