【问题标题】:Blob.decode with replacement does not seem to work带替换的 Blob.decode 似乎不起作用
【发布时间】:2019-03-26 08:57:29
【问题描述】:

这段代码:

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 是真的,但是语法对吗?

【问题讨论】:

  • 这个问题得到了我的 +100 声誉。我一直在寻找来自可靠和/或官方来源的答案,希望从像 samcv 这样的核心开发人员那里得到答案,或者从其他提供核心开发人员讨论(irc 或问题等)链接的人那里得到答案,要么通过注入有关当前有效的方法以及与:replacement:strict 相关的各种编码应该有效的权威响应来纠正或增加我当前答案的价值。看起来原来的积分被浪费了,但如果有人像我希望的那样做,我会很乐意重做。

标签: encoding raku


【解决方案1】:

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_decodeMVM_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++的评论。

【讨论】:

  • 并不是不使用它们。只是我不知道它们是如何使用的,所以我无法编写解释它们作用的文档。而且我知道这些字符超出了表示的范围。这就是替换的目的:替换那些字符(或者这就是我的想法,以及底层 NQP 代码的工作方式)
  • 再次感谢您的回答,但这不是使用的代码。它是一个 Blob,它有自己的代码。不过,它非常相似...同样,我从该代码中收集到的是它应该替换任何无法通过的代码点。测试也指向了这个方向。
  • 对问题的 latin1 部分的更准确答案是 Blob.new 默认为 Blob[uint8].new,这会将传递的值截断为 8 位。这就是你得到¬ 的原因,因为这就是0xac 编码的内容
  • @jjmerelo "$replacement 没有区别。"根据我对 MoarVM 代码和 cmets 的阅读,它适用于两种 windows 编码和 shiftjis 编码,但不适用于 ascii 和 latin1 等其他编码。我已对问题进行了编辑,以使我的答案尽可能清晰。
猜你喜欢
  • 2015-06-10
  • 2020-04-12
  • 2015-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 2010-11-16
  • 1970-01-01
相关资源
最近更新 更多