Blob.decode с заменой вроде не работает - PullRequest
8 голосов
/ 26 марта 2019

Этот код:

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

Просто, похоже, не работает, заменив € на ¬.

Это правда, что эти методы не проверены , но синтаксис правильный?

1 Ответ

7 голосов
/ 26 марта 2019

TL; DR :

  • Только samcv или какой-либо другой основной разработчик может дать достоверный ответ.Это мое понимание кода, комментариев и результатов, которые я вижу.

  • Если мое понимание правильное, необходимо разобраться с каким-то документом и / или кодом, чтобы воспроизвести этот SO спорный вопрос. 1

  • Задание аргумента $replacement соответствует другому многопараметрическому методу P6, чем это невозможно.Давайте назовем его «путь кода замены».

  • Путь кода «замена» передает аргументы $replacement и $strict в путь кода в nqp, который, в свою очередь, передает их напуть кода в бэкэнде, который обрабатывает замены.

  • В бэкэнде MoarVM аргументы замены и строгого режима передаются в декодеры для кодировок windows1252, windows1251 и shiftjis , ноне для других кодировок . 2

по соответствующему пути кода

Ваш код вызывает этот код в 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 в ops.c.

Это, в свою очередь, вызывает MVM_string_decode_config в том же файле.

Из комментариев этой последней функции есть пара ключевых предложений, которые предположительно объясняютАктуальность замены и аргументы строгости:

Unlike MVM_string_decode, он не будет проходить через кодовые точки, которые не имеют официального отображения.

На данный момент Windows-1252 и Windows-1251 - единственные, на которых есть разница.

Из-за написания кода и коммитов в репозитории последний комментарий немного устарел, потому что похоже, что он должен иметь значение и для shiftjis.

Также, чтобы было понятно, если указать $replacement аргумент в P6, тогда аргумент $strict в конечном итоге будет игнорироваться (и предполагается $strict = True) при декодировании любой кодировки, кроме кодировок windows или shiftjis. 2

Что происходит с ascii и latin1, в частности

Текущий код для MVM_string_decode_config не передает аргументы замены / строгости в функции MVM_string_ascii_decode и MVM_string_latin1_decode.

Таким образом, если вы используете кодировку «ascii», то двоичный объект должен содержать только значения от 0 до 127, а для «latin1» значения должны быть в диапазоне от 0 до 255.

say "þor".ords; # (254 111 114)
say "3€".ords;  # (51 8364)

Первыйстрока (какBuf) не удается декодировать, и вместо этого выдает сообщение об ошибке, потому что 254 больше 127 и код декодера ascii в MoarVM реагирует на недопустимое значение, выдавая исключение с «недопустимым ASCII»сообщение.

Второй заменяет на ¬.Это связано с тем, что по умолчанию Buf представляет собой 8-битный массив, поэтому значение выше 255 усекается до его младшего байта, что для совпадает с ¬ (как в latin1, так и в Unicode). 3

Но не лучше, если вы используете Buf с большим размером элемента.Результат по-прежнему ¬ в сочетании с тофу .Я могу видеть, даже если я не могу C, так что для меня ясно, что функция MVM_string_latin1_decode в MoarVM , которая декодирует latin1, не генерирует исключения.Таким образом, по-видимому, когда он встречает символьные значения вне диапазона 0-255, он превращает старшие байты в тофу.

Сноски

1 Конечно, JJ делает именно то, что делаетзаставил их опубликовать это ТАК, в первую очередь это исправление документа.Я добавил эту сноску, чтобы другие более поздние читатели поняли этот контекст и осознали, что этот SO ведет к изменениям в документе и может привести к изменениям в коде, что, по-видимому, сделает этот SO спорным из-за проделанной работы.

2 Было бы неплохо, если бы Multis отклонил использование аргумента $replacement, если декодер для указанной кодировки ничего с этим не делает.

3 См. Комментарий timotimo ++ ниже.

...