Apakah ini Valid Dimodifikasi UTF-8?

9

UTF-8 adalah cara yang relatif sederhana untuk menyandikan titik kode Unicode dalam format lebar variabel sehingga tidak mudah membingungkan kode yang tidak disadari Unicode.

Ikhtisar UTF-8

  • Byte dalam kisaran 1-0x7F, inklusif, biasanya valid
  • Bytes dengan pola bit 10XX XXXXdianggap sebagai byte lanjutan, dengan enam bit paling tidak signifikan yang digunakan untuk mengkodekan bagian dari codepoint. Ini tidak boleh muncul kecuali mereka diharapkan oleh byte sebelumnya.
  • Bytes dengan pola 110X XXXXmengharapkan satu byte kelanjutan sesudahnya
  • Bytes dengan pola 1110 XXXXmengharapkan dua byte lanjutan setelahnya
  • Bytes dengan pola 1111 0XXXmengharapkan tiga byte lanjutan setelahnya
  • Semua byte lainnya tidak valid dan seharusnya tidak muncul di mana pun dalam aliran UTF-8. Cluster 5, 6, dan 7 byte dimungkinkan secara teori, tetapi tidak akan diizinkan untuk keperluan tantangan ini.

Pengkodean terlalu lama

UTF-8 juga mensyaratkan bahwa codepoint harus diwakili dengan jumlah byte minimum. Urutan byte apa pun yang dapat diwakili dengan byte lebih sedikit tidak valid. UTF-8 yang dimodifikasi menambahkan satu pengecualian untuk ini untuk karakter nol (U + 0000), yang harus direpresentasikan sebagai C0 80(representasi hex)), dan sebagai gantinya melarang byte nol muncul di mana saja di aliran. (Ini membuatnya kompatibel dengan string yang diakhiri null)

Tantangan

Anda harus membuat program yang, ketika diberi string byte, akan menentukan apakah string tersebut mewakili UTF-8 yang Dimodifikasi yang valid dan akan mengembalikan nilai kebenaran jika valid dan nilai falsy sebaliknya. Perhatikan bahwa Anda harus memeriksa penyandian yang terlalu lama dan byte nol (karena ini Dimodifikasi UTF-8). Anda tidak perlu mendekodekan nilai UTF-8.

Contohnya

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')

Aturan

  • Aturan dan celah standar berlaku
  • Input dan output dapat dalam format apa pun asalkan semua nilai dalam rentang byte yang tidak ditandatangani (0-255) dapat dibaca.
    • Anda mungkin perlu menggunakan array atau file daripada string yang diakhiri dengan nol. Anda harus bisa membaca byte nol.
  • Kode terpendek menang!
  • Perhatikan bahwa menggunakan bawaan untuk mendekode UTF-8 tidak dijamin untuk memenuhi persyaratan yang diberikan di sini. Anda mungkin perlu mengatasinya dan membuat case khusus.

EDIT: bonus tambahan untuk tidak menggunakan builtin yang memecahkan kode UTF-8

EDIT2: menghapus bonus karena hanya jawaban Rust yang memenuhi syarat dan aneh untuk didefinisikan.

Beefster
sumber
Saya sudah menunggu yang satu ini.
Adám
Anda mungkin ingin menambahkan test case dengan byte yang tidak valid di kisaran 0xF8-0xFF.
Arnauld
2
Tampaknya pengganti (0xD800 - 0xDFFF) dan codepoints di luar 0x10FFFF diperbolehkan, bertentangan dengan spesifikasi UTF-8 "modern". Saya pikir ini harus diklarifikasi, idealnya dengan kasus uji tambahan.
nwellnhof
lebih banyak contoh akan membantu
don bright
"Bytes dalam kisaran 0-0x7F, inklusif, biasanya valid" apakah itu seharusnya 1 hingga 0x7f?
don bright

Jawaban:

2

Elixir , 69 byte

import String
&valid? replace replace(&1,<<0>>,"\xFF"),"\xC0\x80","0"

Cobalah online!

Menggunakan fungsi validasi string bawaan. Mengambil input sebagai biner Elixir.

Kirill L.
sumber
1

APL (Dyalog Unicode) , 41 39 byte SBCS

Fungsi awalan diam-diam anonim. Mengambil string Unicode sebagai argumen di mana poin kode karakter mewakili byte input.

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

Cobalah online!

'À\x80'⎕R⎕AR eplace C0 80s dengan huruf besar A lphabet

{... } terapkan fungsi anonim berikut, di mana argumennya adalah :

0:: jika terjadi kesalahan:

  0 mengembalikan nol

 mencoba:

  ⎕UCS⍵ konversikan string ke poin kode

  'UTF-8'⎕UCS⍣2 menafsirkan sebagai UTF-8 byte dan mengonversi teks yang dihasilkan kembali ke byte

  ⌊/ byte terendah (nol jika null byte hadir, positif jika tidak, "infinity" jika string kosong)

  × tanda (nol jika null byte hadir, satu jika tidak)

Adm
sumber
Bukankah ini mengembalikan kebenaran untuk D9 C0 80 84 C0 80 10?
Neil
@Neil Memang. Apakah itu salah karena menghapus C0 80membuat byte yang tidak terkait berbatasan dengan cara yang valid, meskipun tidak valid saat dipisahkan? Sunting: Diperbarui untuk memperbaikinya tanpa biaya byte.
Adám
beberapa karakter muncul di layar saya hanya sebagai persegi panjang atau kotak, apakah itu normal? saya di firefox di linux. APL adalah bahasa yang sangat menarik.
jangan terang
@donbright Dalam pengalaman saya, karakter APL selalu ditampilkan dengan benar, meskipun terkadang kurang indah, jadi kotak-kotak itu mungkin hanya Quad s yang seharusnya ada empat dalam kode utama. Seharusnya render seperti ini . Dan ya, APL luar biasa, dan sangat menyenangkan. Anda dapat dengan mudah dan cepat mempelajarinya juga - datang saja di APL Orchard .
Adám
ya mereka paha depan. Terima kasih.
jangan terang
0

Python 2 , 104 102 byte

''.join(chr(int(c,16))for c in input().replace('00','-').replace('C0 80','0').split()).decode('utf-8')

Cobalah online!

Keluaran melalui kode keluar

TFeld
sumber
0

Karat - 191 byte 313 byte

Per komentar di bawah yang asli tidak berfungsi dengan baik. Versi baru dan lebih baik. Tidak ada perpustakaan yang digunakan, karena Perkasa Perkasa Tidak Perlu Untuk Anda dan Perpustakaan Anda. Kode ini menggunakan pencocokan pola dengan mesin negara. Dengan tanpa malu-malu merobek spec UTF8 , setelah menemukannya melalui referensi dan diskusi oleh Jon Skeet , kita dapat menyalin spec hampir karakter untuk karakter ke blok pencocokan pola karat. Pada akhirnya, kami menambahkan persyaratan Mutf8 khusus Beefster untuk C0 80 agar dianggap valid. Tidak Disatukan:

/* 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;

coba di taman bermain karat

jangan cerah
sumber
Alat peraga untuk melakukannya secara manual, tapi saya pikir cek berlebih Anda salah.
Beefster
Tantangan Anda, tuan, memprovokasi saya untuk meniru, dan saya menyimpulkan surat ini dengan menantang Anda, pada gilirannya, untuk memperbaiki seorang pria yang akan mengekspos pertanyaan Anda secara lebih blak-blakan ( bit.ly/2T8tXhO )
don bright