TL;DR:
-
只有 samcv 或其他一些核心开发人员可以提供权威的答案。这是我对看到的代码、cmets和结果的理解。
-
如果我的理解是正确的,则需要整理一些文档和/或代码以呈现此 SO 没有实际意义。1
-
指定 $replacement 参数匹配不同的 P6 核心多方法,而不是不这样做。我们称它为“替换器”代码路径。
-
“替换器”代码路径将 $replacement 和 $strict 参数传递到 nqp 中的代码路径,然后将它们传递到后端处理替换的代码路径。
-
在 MoarVM 后端,replacement 和 strict 参数被传递给 windows1252、windows1251 和 shiftjis 编码的解码器而不是其他编码。2
遵循相关代码路径
您的代码调用this code in Buf.pm6:
multi method decode(Blob:D: $encoding,
Str :$replacement!,
Bool:D :$strict = False) {
nqp::p6box_s(
nqp::decoderepconf(
self,
Rakudo::Internals.NORMALIZE_ENCODING($encoding),
$replacement.defined ?? $replacement !! nqp::null_s(),
$strict ?? 0 !! 1))
}
nqp::decoderepconf函数直接映射到后端对应的函数。
在 MoarVM 后端,它是MVM_string_decode_from_buf_config in ops.c。
这反过来又在同一个文件中调用MVM_string_decode_config。
从后一个函数的 cmets 中,有几个关键句子可能解释了替换和严格参数的相关性:
与MVM_string_decode不同,它不会通过没有官方映射的代码点。
目前只有 windows-1252 和 windows-1251 会有所不同。
在 repo 中解释代码和提交表明后一条评论有点过时了,因为它看起来也应该对 shiftjis 产生影响。
另外,需要明确的是,如果在 P6 中指定 $replacement 参数,那么如果解码除 windows 或 shiftjis 编码之外的任何编码,$strict 参数最终将被忽略(并且假定 $strict = True) .2
特别是 ascii 和 latin1 会发生什么
MVM_string_decode_config 的当前代码不将替换/严格参数传递给MVM_string_ascii_decode 和MVM_string_latin1_decode 函数。
因此,如果您使用编码“ascii”,则 blob 只能包含 0 到 127 之间的值,而“latin1”的值必须介于 0 到 255 之间。
say "þor".ords; # (254 111 114)
say "3€".ords; # (51 8364)
第一个字符串(作为Buf)无法解码,而是产生错误消息,因为 254 大于 127,并且the ascii decoder code in MoarVM 通过抛出带有“无效 ASCII”消息的异常来对无效值做出反应.
第二个将€ 替换为¬。这是因为默认情况下 Buf 是一个 8 位数组,因此高于 255 的值会被截断为其低字节,对于 € 与 ¬ 相同(在 latin1 和 Unicode 中)。 3
但如果您使用具有更大元素大小的Buf 也不会更好。结果仍然是¬,结合tofu。即使我不能 C 我也可以看到,所以我很清楚解码 latin1 的the MVM_string_latin1_decode function in MoarVM 不会引发异常。所以大概当它遇到 0-255 范围之外的字符值时,它会将较高的字节变成豆腐。
脚注
1 当然,JJ 所做的正是导致他们首先发布此 SO 的事情是修复文档。我添加了这个脚注,以便其他后来的读者能够理解上下文并意识到这个 SO 会导致文档发生变化,并且可能会导致代码发生变化,这可能会由于所做的工作而导致这个 SO 没有实际意义。
2 如果指定编码的解码器不使用它,那么如果有多个拒绝使用$replacement 参数,那就太好了。
3见下面timotimo++的评论。