此代码:
my $þor-blob = Blob.new("þor".ords);
$þor-blob.decode( "ascii", :replacement("0"), :strict(False) ).say
失败:
Will not decode invalid ASCII (code point > 127 found)
还有一个:
my $euro = Blob.new("3€".ords);
$euro.decode( "latin1", :replacement("euro") ).say
似乎根本行不通,用¬代替€。
those methods are not tested是正确的,但是语法正确吗?
答案 0 :(得分:7)
TL; DR :
只有samcv或其他核心开发人员才能提供权威的答案。这是我对所看到的代码,注释和结果的理解。
如果我的理解是正确的,则需要整理一些文档和/或代码以呈现此SO主题。 1
指定$replacement
参数与不同的P6核心多重方法匹配。我们称它为“替换”代码路径。
“替换”代码路径将$replacement
和$strict
参数传递到nqp中的代码路径,然后将其传递到后端中处理替换的代码路径。
在MoarVM后端,对于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
。
从后一个函数的注释中,有几个关键句子大概可以解释替换和严格性参数的相关性:
与
MVM_string_decode
不同,它不会通过没有正式映射的代码点。目前只有Windows-1252和Windows-1251可以发挥作用。
对代码进行拼写并提交到回购中,表明后者的注释有些过时了,因为它似乎也应该对shiftjis有所帮助。
此外,要明确一点,如果在P6中指定了$replacement
参数,则如果解码其他编码,则$strict
参数将最终被忽略(并假设$strict = True
)而不是Windows或shiftjis编码。 2
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,所以对我来说很清楚the MVM_string_latin1_decode
function in MoarVM解码latin1不会引发异常。因此,大概是当遇到字符值超出0-255的范围时,它会将较高的字节转换为豆腐。
1 当然,JJ所做的正是使他们首先发布此SO的事情是修复了文档。我添加了此脚注,以便其他后来的读者理解该上下文并意识到此SO导致文档中的更改,并且可能导致代码更改,这可能由于完成的工作而使SO毫无意义。 >
2 如果指定编码的解码器不对其进行任何操作,如果有多个拒绝使用$replacement
参数,那就太好了。
3 参见下面的timotimo ++评论。