Чи дійсно модифікований UTF-8?


9

UTF-8 - це досить простий спосіб кодування точок коду Unicode у форматі змінної ширини, таким чином, що він не може легко сплутати код, про який не знає Unicode.

Огляд UTF-8

  • Байти в діапазоні 1-0x7F включно, як правило, дійсні
  • Байти з бітовим малюнком 10XX XXXXвважаються байтами продовження, при цьому шість найменш значущих бітів використовуються для кодування частини кодової точки. Вони не повинні з'являтися, якщо їх не очікує попередній байт.
  • Байти з візерунком 110X XXXXочікують одного байта продовження після цього
  • Байти з малюнком 1110 XXXXочікують два наступні байти
  • Байти з малюнком 1111 0XXXочікують три байти продовження
  • Усі інші байти є недійсними і не повинні з’являтися ніде в потоці UTF-8. Теоретично можливі кластери 5, 6 і 7 байтів, але це не буде дозволено для цілей цього виклику.

Надмірне кодування

UTF-8 також вимагає, щоб кодова точка була представлена ​​мінімальною кількістю байтів. Будь-яка послідовність байтів, яка могла бути представлена ​​меншою кількістю байтів, не є дійсною. Модифікований UTF-8 додає один виняток до цього для нульових символів (U + 0000), який має бути представлений у вигляді C0 80(шістнадцяткове представлення)), а замість цього забороняє нульові байти з’являтися в будь-якому місці потоку. (Це робить його сумісним з нульовими строками)

Виклик

Ви повинні створити програму, яка при наданні рядка байтів визначить, чи є ця строка дійсною Модифікованою UTF-8 і поверне триєдине значення, якщо дійсне, а фальш-значення - інакше. Зауважте, що ви повинні перевірити наявність довгих кодувань та нульових байтів (оскільки це модифікований UTF-8). Вам не потрібно розшифровувати значення UTF-8.

Приклади

41 42 43  ==> yes (all bytes are in the 0-0x7F range)
00 01 02  ==> no (there is a null byte in the stream)
80 7F 41  ==> no (there is a continuation byte without a starter byte)
D9 84 10  ==> yes (the correct number of continuation bytes follow a starter byte)
F0 81 82 41  ==> no (there are not enough continuation bytes after F0)
EF 8A A7 91  ==> no (too many continuation bytes)
E1 E1 01  ==> no (starter byte where a continuation byte is expected)
E0 80 87  ==> no (overlong encoding)
41 C0 80  ==> yes (null byte encoded with the only legal overlong encoding)
F8 42 43  ==> no (invalid byte 'F8')

Правила

  • Застосовуються стандартні правила та лазівки
  • Введення та вихід можуть бути у будь-якому зручному форматі до тих пір, поки всі значення в діапазоні непідписаних байтів (0-255) можуть бути прочитані.
    • Можливо, вам доведеться використовувати масив або файл, а не рядок з нульовим завершенням. Потрібно вміти читати нульові байти.
  • Найкоротший код виграє!
  • Зауважте, що використання вбудованих файлів для декодування UTF-8 не гарантовано відповідає вимогам, наведеним тут. Можливо, вам доведеться обійтись і створити спеціальні кейси.

EDIT: доданий бонус за невикористання вбудованих файлів, які декодують UTF-8

EDIT2: вилучено бонус, оскільки лише відповідь "Іржа" кваліфікована, і визначити це незручно.


Я чекав цього.
Адам

Ви можете додати тестовий випадок з недійсним байтом у діапазоні 0xF8-0xFF.
Арнольд

2
Схоже, що сурогати (0xD800 - 0xDFFF) та кодові точки, що перевищують 0x10FFFF, дозволені, всупереч "сучасній" специфікації UTF-8. Я думаю, що це слід уточнити, в ідеалі - з додатковими тестовими випадками.
nwellnhof

більше прикладів було б корисно
яскравий

"Байти в діапазоні 0-0x7F включно, як правило, є дійсними", це має бути від 1 до 0x7f?
яскравий

Відповіді:



1

APL (Dyalog Unicode) , 41 39 байт SBCS

Функція анонімного мовчазного префікса. В якості аргументу береться рядок Unicode, де кодові точки символів представляють вхідні байти.

{0::0⋄×⌊/'UTF-8'UCS2UCS⍵}'À\x80'RA

Спробуйте в Інтернеті!

'À\x80'⎕R⎕AR eplace C0 80з з великої A lphabet

{} Застосувати таку анонімну функцію, де аргументом є :

0:: якщо трапляється якась помилка:

  0 повернути нуль

 спробуйте:

  ⎕UCS⍵ перетворити рядок у кодові точки

  'UTF-8'⎕UCS⍣2 інтерпретувати як UTF-8 байт та перетворювати отриманий текст назад у байти

  ⌊/ найнижчий байт (нуль, якщо є нульовий байт, позитивний, якщо ні, "нескінченність", якщо порожній рядок)

  × знак (нуль, якщо нульовий байт присутній, один якщо ні)


Хіба це не повернеться D9 C0 80 84 C0 80 10?
Ніл

@Neil Це дійсно так. Це неправильно, тому що видалення C0 80робить непов'язані байти суміжними таким чином, що є дійсним, хоча вони є недійсними, коли вони відокремлені? Редагувати: оновлено, щоб виправити це без витрат на байт.
Адам

деякі персонажі з’являються на моєму екрані як просто прямокутники або поля, це нормально? я в Firefox на Linux. APL - дуже цікава мова.
Дон яскравий

@donbright На мій досвід, символи APL завжди відображаються правильно, навіть якщо іноді менше, ніж красиво, тому ці поля, ймовірно, просто квадроцикли , яких у головному коді має бути чотири. Це має бути таким чином . І так, APL - це дивовижно, і дуже весело. Ви також можете легко і швидко дізнатися це - просто заходьте в сад APL .
Адам

так, вони квадроцикли. Дякую.
яскравий


0

Іржа - 191 байт 313 байт

За коментарем нижче оригіналу не працювало належним чином. Нова та вдосконалена версія. Ніякі бібліотеки не використовуються, оскільки Могутня іржа не потребує вас і ваших бібліотек. Цей код використовує відповідність шаблону зі станковою машиною. За безсоромно зриваючи UTF8 специфікації , після того, як знайти його з допомогою посилання і обговорення Jon тарілочках , можна скопіювати специфікацію майже посимвольний в матчі блоку відповідності шаблон іржі. Наприкінці ми додаємо до спеціальної вимоги Mutf8 Beefster про те, що C0 80 вважається дійсним. Безголівки:

/* http://www.unicode.org/versions/corrigendum1.html
 Code Points        1st Byte    2nd Byte    3rd Byte    4th Byte
U+0000..U+007F      00..7F           
U+0080..U+07FF      C2..DF      80..BF           
U+0800..U+0FFF      E0          A0..BF      80..BF       
U+1000..U+FFFF      E1..EF      80..BF      80..BF       
U+10000..U+3FFFF    F0          90..BF      80..BF      80..BF
U+40000..U+FFFFF    F1..F3      80..BF      80..BF      80..BF
U+100000..U+10FFFF  F4          80..8F      80..BF      80..BF
*/

let m=|v:&Vec<u8>|v.iter().fold(0, |s, b| match (s, b) {
        (0, 0x01..=0x7F) => 0,
        (0, 0xc2..=0xdf) => 1,
        (0, 0xe0) => 2,
        (0, 0xe1..=0xef) => 4,
        (0, 0xf0) => 5,
        (0, 0xf1..=0xf3) => 6,
        (0, 0xf4) => 7,
        (1, 0x80..=0xbf) => 0,
        (2, 0xa0..=0xbf) => 1,
        (4, 0x80..=0xbf) => 1,
        (5, 0x90..=0xbf) => 4,
        (6, 0x80..=0xbf) => 4,
        (7, 0x80..=0x8f) => 4,
        (0, 0xc0) => 8, // beefster mutf8 null
        (8, 0x80) => 0, // beefster mutf8 null
        _ => -1,
    })==0;

спробуйте на ігровій майданчику


Реквізити для того, щоб це зробити вручну, але я вважаю, що ваша перевірка задовгості неправильна.
Beefster

Ваш виклик, шановний пане, провокує мене до наслідування, і я закінчую цей лист, кидаючи виклик вам, у свою чергу, звернутися до людини, який викладе ваше питання більш грубо ( bit.ly/2T8tXhO )
яскравий
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.