Применение искинов - шоссе империализма (Стенгазета русификаторов ИТ)

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



Использует ли Павиа ДКА для разбора UTF-8

Сообщений 1 страница 8 из 8

1

[html]
<a href="https://forum.sources.ru/index.php?s=6e172320741a32d0fc72511e3c1061e7&amp;showtopic=325997&view=findpost&p=2833524">про ДКА</a>,
<a href="https://forum.sources.ru/index.php?showtopic=325997&view=findpost&p=2832469">про bison</a>[/html]

Это вопрос к знатокам паскаля - найти этот автомат в тексте компилятора ПОП.
[html]<a href="https://gitlab.com/pavia00/pop/blob/master/src/Scaner/UScaner.pas">https://gitlab.com/pavia00/pop/blob/master/src/Scaner/UScaner.pas</a>[/html]

Отредактировано Лис (2019-03-26 20:37:54)

0

2

https://gitlab.com/pavia00/pop/blob/mas … r.pas#L611

https://gitlab.com/pavia00/pop/blob/mas … r.pas#L383

Сам класс TSimvler является ДКА. У него всего 1 текущее состояние хронящеяся в счётчике команд процессора.  Хотя конечно тут нету явных структур  типа TState. Поэтому по своей природе такой тексторез ближе к алгоритмическому подходу.

0

3

Павиа написал(а):

У него всего 1 текущее состояние

По стандарту RFC 3629 кодировки длина символа может составлять до 4 байт
[html]<a href="https://stijndewitt.com/2014/08/09/max-bytes-in-a-utf-8-char/">https://stijndewitt.com/2014/08/09/max-bytes-in-a-utf-8-char/</a>[/html]Это означает, что в автомате должно быть минимум 2 состояния (потому что ошибочные символы, например без последнего байта, должны заменяться на ОДИН замещающий символ).

CESU-8
Кроме того, обработка отдельных codepoint это ещё не всё, и должен быть желательно иметь второй ДКА-автомат, который позволяет разбирать последовательности codepoint-ов. Для русского языка это важно для обработки ударений и альтернативной кодировки для букв с диактриками.
http://unicode.org/faq/utf_bom.html#utf8-4

Кроме того, имелись в виду, наверное, состояния автомата, отличающиеся от начального (на это намекает слово "текущее" в словосочетании "текущее состояние"). Потому что автомат с одним состоянием только в этом одном состоянии и может находится. Поэтому Павиа, видимо имеет в виду, что у него в автомате два состояния - начальное и текущее. А я соответственно, что нужны состояния "начальное", "после первого байта", "после второго байта". Нужно ли состояние "после третьего байта" - это дискуссионный вопрос.

Если к коду Павиа присмотреться, у него там тоже байты не только нулевой и первый, но и второй есть.

[html]<pre>
function TFileSimvler.ReadNextChar: TSimvlerChar;
     var B0, B1, B2:Byte;
begin
    repeat
        B0:=ReadByte;
    until (B0 and $C0<>$D0); // UTF-8  .

    if (B0 and $80)=$00 then
    begin
        Result:=TSimvlerChar(B0);
    end
    else  <b>&lt;----- переход в первое состояние, отличное от начального</b>
        if (B0 and $E0)=$C0 then
        begin
            B1:=ReadByte;
            Result:=TSimvlerChar((B1 and $3F) + (B0 and $1F) shl 6);
        end
        else  <b>&lt;----- переход во второе состояние, отличное от начального</b>
            if (B0 and $F0)=$E0 then
            begin
                B1:=ReadByte;
                B2:=ReadByte;
                Result:=TSimvlerChar((B2 and $3F) + (B1 and $3F) shl 6 + (B0 and $1F) shl 12);
            end;
    Inc(FPosCol);
end;
</pre>[/html]

Строки, хранение и обработка
Символы с кодами от 128 кодируются 2-мя байтами, с кодами от 2048 — 3-мя, от 65536 — 4-мя.
0x00000000 — 0x0000007F: 0xxxxxxx
0x00000080 — 0x000007FF: 110xxxxx 10xxxxxx
0x00000800 — 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
0x00010000 — 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

т.е. в первом байте мы смотрим на восьмой бит, а затем на шестой бит.
0x80 = 0b10000000
0xC0 = 0b11000000
0xE0 = 0b11100000
0xF0 = 0b11110000

Отредактировано Лис (2019-03-27 19:04:48)

0

4

Смысл странного цикла вначале мне не ясен.
Потому что если байт обрезать по маске $C0 он уже никогда не станет равен $D0 (11010000).
Т.е. условие выполняется всегда (условие выхода из цикла всегда истинно), и
этот цикл всегда выполняется ровно один раз.

Наверное это бага, и там должна быть проверка <>$80 вместо <>$D0 для того, чтобы пропускать средние байты многобайтовых символов.

И ещё я не вижу обработки некорректно составленных входных файлов (т.е. кода для диагностики, сообщений пользователю). Т.е. в этом цикле Repeat должен быть вывод сообщения, что в такой-то позиции текста пропущен символ с таким-то кодом.

Отредактировано Лис (2019-03-27 19:10:17)

0

5

Ну да видимо ошибка. Нужно поправить, но у меня пока времени не хватает. Нужно срочно векторный редактор доделать.

Отредактировано Павиа (2019-03-28 12:03:09)

0

6

Павиа написал(а):

Нужно поправить, но у меня пока времени не хватает.

Чем больше я в этот код вглядываюсь, тем мне страшнее.
Допустим, что нам встретился многобайтовый символ в конце файла, но там только заголовочный байт, а остальные пропущены.
По стандарту его надо аккуратно проигнорировать.
Но у тебя функция ReadByte не имеет права на ошибку (если из файла считано 0 байт, то она вернёт мусор из буфера).

Кроме того, считанные байты продолжения не проверяются на содержимое 2-х старших битов. Они просто отрезаются по маске без проверки. Если они были неправильные, то парсер ведёт себя не по стандарту.

Если считывать по одному codepoint, то нужно уметь "расчитывать" ("развидеть") байт. Это нужно для того, чтобы вернуть codepoint "некорректный символ" (чтобы потом начать читать новый codepoint не пропуская уже считанный корректный байт, следующий сразу после некорректно закодированного символа).

Отредактировано Лис (2019-04-02 13:39:14)

0

7

Лис написал(а):

Кроме того, считанные байты продолжения не проверяются на содержимое 2-х старших битов. Они просто отрезаются по маске без проверки. Если они были неправильные, то парсер ведёт себя не по стандарту.

Конкретный пункт стандарта покажите.

Лис написал(а):

Если считывать по одному codepoint, то нужно уметь "расчитывать" ("развидеть") байт. Это нужно для того, чтобы вернуть codepoint "некорректный символ"

А зачем? У меня код проста устраняет единичные сбои - это лучше.

Лис написал(а):

чтобы потом начать читать новый codepoint не пропуская уже считанный корректный байт, следующий сразу после некорректно закодированного символа

При передачи и хранении 1 байт пропасть не может. Происходит только единичная инверсия бит согласно модели канала.

Лис написал(а):

Но у тебя функция ReadByte не имеет права на ошибку (если из файла считано 0 байт, то она вернёт мусор из буфера).

И? Если последний символ был '.' а пришел мусор, то его проверит грамматический анализ и заругается на ошибочный символ. А если это после точки. То тексторезу безраницы, он после 'end.' перестанет читать.

0

8

Павиа написал(а):

Конкретный пункт стандарта покажите.

Implementations of the decoding algorithm above MUST protect against
decoding invalid sequences. For instance, a naive implementation may
decode the overlong UTF-8 sequence C0 80 into the character U+0000,
or the surrogate pair ED A1 8C ED BE B4 into U+233B4. Decoding
invalid sequences may have security consequences or cause other
problems. See Security Considerations (Section 10)

это RFC 3629, который является частью стандарта ISO

Отредактировано Лис (2022-11-19 04:03:24)

0