Di tempat kerja sepertinya tidak ada minggu yang berlalu tanpa beberapa konipsi terkait pengkodean, bencana, atau malapetaka. Masalahnya biasanya berasal dari programmer yang mengira mereka dapat memproses file "teks" dengan andal tanpa menentukan encodingnya. Tapi Anda tidak bisa.
Jadi diputuskan untuk sejak saat itu melarang file memiliki nama yang berakhiran *.txt
atau *.text
. Pemikirannya adalah bahwa ekstensi tersebut menyesatkan programmer kasual menjadi kepuasan yang tumpul tentang pengkodean, dan ini mengarah pada penanganan yang tidak tepat. Hampir lebih baik tidak memiliki ekstensi sama sekali, karena setidaknya Anda tahu bahwa Anda tidak tahu apa yang Anda miliki.
Namun, kami tidak akan pergi sejauh itu. Sebagai gantinya, Anda diharapkan menggunakan nama file yang diakhiri dengan encoding. Jadi untuk file teks, misalnya, ini akan menjadi sesuatu seperti README.ascii
, README.latin1
, README.utf8
, dll
Untuk file yang membutuhkan ekstensi tertentu, jika seseorang dapat menentukan pengkodean di dalam file itu sendiri, seperti di Perl atau Python, maka Anda harus melakukannya. Untuk file seperti sumber Java yang tidak memiliki fasilitas internal untuk file tersebut, Anda harus meletakkan pengkodean sebelum ekstensi, seperti SomeClass-utf8.java
.
Untuk keluaran, UTF-8 sangat disukai.
Tetapi sebagai masukan, kita perlu mencari cara untuk menangani ribuan file dalam basis kode kita yang diberi nama *.txt
. Kami ingin mengubah nama semuanya agar sesuai dengan standar baru kami. Tapi kita tidak mungkin melihat semuanya. Jadi kita membutuhkan perpustakaan atau program yang benar-benar berfungsi.
Ini beragam dalam ASCII, ISO-8859-1, UTF-8, Microsoft CP1252, atau Apple MacRoman. Meskipun kami tahu kami dapat mengetahui apakah sesuatu itu ASCII, dan kami memiliki perubahan yang baik dalam mengetahui apakah sesuatu mungkin UTF-8, kami bingung tentang pengkodean 8-bit. Karena kami berjalan di lingkungan Unix campuran (Solaris, Linux, Darwin) dengan sebagian besar desktop adalah Mac, kami memiliki beberapa file MacRoman yang mengganggu. Dan ini khususnya merupakan masalah.
Untuk beberapa waktu sekarang saya telah mencari cara untuk menentukan secara terprogram dari
- ASCII
- ISO-8859-1
- CP1252
- MacRoman
- UTF-8
ada file di dalamnya, dan saya belum menemukan program atau pustaka yang dapat diandalkan untuk membedakan antara ketiga penyandiaksaraan 8-bit yang berbeda. Kami mungkin memiliki lebih dari seribu file MacRoman saja, jadi detektor charset apa pun yang kami gunakan harus dapat mengendusnya. Tidak ada yang bisa saya lihat yang bisa mengatur triknya. Saya memiliki harapan besar untuk perpustakaan detektor charset ICU , tetapi tidak dapat menangani MacRoman. Saya juga telah melihat modul untuk melakukan hal yang sama di Perl dan Python, tetapi lagi dan lagi ceritanya selalu sama: tidak ada dukungan untuk mendeteksi MacRoman.
Oleh karena itu, yang saya cari adalah pustaka atau program yang ada yang andal menentukan mana dari lima penyandiaksaraan file itu — dan sebaiknya lebih dari itu. Secara khusus itu harus membedakan antara tiga pengkodean 3-bit yang telah saya kutip, terutama MacRoman . File-file tersebut lebih dari 99% teks bahasa Inggris; ada beberapa dalam bahasa lain, tetapi tidak banyak.
Jika itu adalah kode pustaka, preferensi bahasa kami adalah Perl, C, Java, atau Python, dan dalam urutan itu. Jika ini hanya sebuah program, maka kami tidak terlalu peduli dengan bahasanya asalkan datang dalam sumber penuh, berjalan di Unix, dan sepenuhnya tidak terbebani.
Apakah ada orang lain yang memiliki masalah jutaan file teks lama yang dikodekan secara acak? Jika ya, bagaimana Anda mencoba mengatasinya, dan seberapa sukses Anda? Ini adalah aspek terpenting dari pertanyaan saya, tetapi saya juga tertarik pada apakah menurut Anda mendorong pemrogram untuk memberi nama (atau mengganti nama) file mereka dengan penyandian sebenarnya untuk file tersebut akan membantu kami menghindari masalah di masa mendatang. Adakah yang pernah mencoba untuk menegakkan ini secara kelembagaan, dan jika ya, apakah itu berhasil atau tidak, dan mengapa?
Dan ya, saya sangat memahami mengapa seseorang tidak dapat menjamin jawaban yang pasti mengingat sifat masalahnya. Ini terutama terjadi pada file kecil, di mana Anda tidak memiliki cukup data untuk melanjutkan. Untungnya, file kami jarang berukuran kecil. Selain README
file acak , sebagian besar berukuran antara 50k hingga 250k, dan banyak yang lebih besar. Apa pun yang berukuran lebih dari beberapa K dijamin akan menggunakan bahasa Inggris.
Domain masalahnya adalah penambangan teks biomedis, jadi terkadang kita berurusan dengan korpora yang luas dan sangat besar, seperti semua penyimpanan Akses Terbuka PubMedCentral. File yang agak besar adalah BioThesaurus 6.0, dengan ukuran 5,7 gigabyte. File ini sangat mengganggu karena hampir semuanya UTF-8. Namun, beberapa numbskull pergi dan terjebak beberapa baris di dalamnya yang ada dalam beberapa pengkodean 8-bit — Microsoft CP1252, saya yakin. Butuh waktu cukup lama sebelum Anda melakukan perjalanan yang satu itu. :(
Jawaban:
Pertama, kasus mudahnya:
ASCII
Jika data Anda tidak berisi byte di atas 0x7F, maka itu ASCII. (Atau pengkodean ISO646 7-bit, tetapi itu sangat usang.)
UTF-8
Jika memvalidasi data Anda sebagai UTF-8, maka Anda dapat dengan aman berasumsi itu adalah UTF-8. Karena aturan validasi ketat UTF-8, positif palsu sangat jarang terjadi.
ISO-8859-1 vs. windows-1252
Satu-satunya perbedaan antara dua pengkodean ini adalah bahwa ISO-8859-1 memiliki karakter kontrol C1 di mana windows-1252 memiliki karakter yang dapat dicetak € ‚„… † ‡ ˆ Š Š ‹ŒŽ ''“ ”• –—˜ ™ š› œžŸ. Saya telah melihat banyak file yang menggunakan tanda kutip keriting atau tanda hubung, tetapi tidak ada yang menggunakan karakter kontrol C1. Jadi jangan repot-repot dengan mereka, atau ISO-8859-1, cukup deteksi windows-1252 sebagai gantinya.
Sekarang Anda hanya memiliki satu pertanyaan.
Bagaimana Anda membedakan MacRoman dari cp1252?
Ini jauh lebih rumit.
Karakter tidak terdefinisi
Byte 0x81, 0x8D, 0x8F, 0x90, 0x9D tidak digunakan di windows-1252. Jika itu terjadi, maka asumsikan datanya adalah MacRoman.
Karakter identik
Byte 0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ) kebetulan sama di kedua pengkodean. Jika ini adalah satu-satunya byte non-ASCII, tidak masalah apakah Anda memilih MacRoman atau cp1252.
Pendekatan statistik
Hitung frekuensi karakter (BUKAN byte!) Dalam data yang Anda ketahui sebagai UTF-8. Tentukan karakter yang paling sering. Kemudian gunakan data ini untuk menentukan apakah karakter cp1252 atau MacRoman lebih umum.
Misalnya, dalam pencarian yang baru saja saya lakukan pada 100 artikel Wikipedia bahasa Inggris acak, karakter non-ASCII yang paling umum adalah
·•–é°®’èö—
. Berdasarkan fakta ini,Hitung byte yang menyarankan cp1252 dan byte yang menyarankan MacRoman, dan gunakan mana yang terbesar.
sumber
Mozilla nsUniversalDetector (Perl bindings: Encode :: Detect / Encode :: Detect :: Detector ) terbukti jutaan kali lipat .
sumber
x-mac-cyrillic
didukung,x-mac-hebrew
dibahas panjang lebar di komentar,x-mac-anything-else
tidak disebutkan.Upaya saya pada heuristik seperti itu (dengan asumsi Anda telah mengesampingkan ASCII dan UTF-8):
Catatan samping:
Jangan lakukan ini!!
Kompilator Java mengharapkan nama file untuk mencocokkan nama kelas, jadi mengganti nama file akan membuat kode sumber tidak dapat dikompilasi. Hal yang benar adalah menebak pengkodean, kemudian menggunakan
native2ascii
alat untuk mengonversi semua karakter non-ASCII menjadi urutan pelolosan Unicode .sumber
*.text
file."Perl, C, Java, atau Python, dan dalam urutan itu": sikap menarik :-)
"Kami memiliki perubahan yang baik dalam mengetahui apakah sesuatu mungkin UTF-8": Sebenarnya kemungkinan bahwa file yang berisi teks bermakna yang dikodekan dalam beberapa rangkaian karakter lain yang menggunakan byte set-bit tinggi akan berhasil didekode karena UTF-8 semakin kecil.
Strategi UTF-8 (dalam bahasa yang paling tidak disukai):
Setelah Anda memutuskan bahwa itu bukan ASCII atau UTF-8:
Detektor charset asal Mozilla yang saya tahu tidak mendukung MacRoman dan bagaimanapun juga tidak melakukan pekerjaan dengan baik pada charset 8-bit terutama dengan bahasa Inggris karena AFAICT mereka bergantung pada memeriksa apakah decoding masuk akal dalam pemberian bahasa, mengabaikan karakter tanda baca, dan berdasarkan pilihan dokumen yang luas dalam bahasa tersebut.
Seperti yang dikatakan orang lain, Anda benar-benar hanya memiliki karakter tanda baca set-bit tinggi yang tersedia untuk membedakan antara cp1252 dan macroman. Saya menyarankan untuk melatih model tipe Mozilla pada dokumen Anda sendiri, bukan Shakespeare atau Hansard atau Alkitab KJV, dan memperhitungkan semua 256 byte. Saya berasumsi bahwa file Anda tidak memiliki markup (HTML, XML, dll) di dalamnya - itu akan mengubah probabilitas menjadi sesuatu yang mengejutkan.
Anda telah menyebutkan file yang sebagian besar UTF-8 tetapi gagal didekode. Anda juga harus sangat curiga terhadap:
(1) file yang diduga dienkode dalam ISO-8859-1 tetapi berisi "karakter kontrol" dalam rentang 0x80 hingga 0x9F inklusif ... ini sangat umum sehingga draf standar HTML5 mengatakan untuk mendekode SEMUA aliran HTML yang dideklarasikan sebagai ISO-8859 -1 menggunakan cp1252.
(2) file yang mendekode OK sebagai UTF-8 tetapi Unicode yang dihasilkan berisi "karakter kontrol" dalam kisaran U + 0080 hingga U + 009F inklusif ... ini dapat dihasilkan dari transcoding cp1252 / cp850 (lihat itu terjadi!) / Etc file dari "ISO-8859-1" ke UTF-8.
Latar belakang: Saya memiliki proyek basah-Minggu-sore untuk membuat detektor charset berbasis Python yang berorientasi file (bukan berorientasi web) dan bekerja dengan baik dengan set karakter 8-bit termasuk
legacy ** n
yang seperti cp850 dan cp437. Ini belum mendekati jam tayang utama. Saya tertarik dengan file pelatihan; apakah file ISO-8859-1 / cp1252 / MacRoman Anda sama-sama "tidak terbebani" seperti yang Anda harapkan dari solusi kode siapa pun?sumber
Seperti yang telah Anda temukan, tidak ada cara sempurna untuk memecahkan masalah ini, karena tanpa pengetahuan implisit tentang pengkodean yang digunakan file, semua pengkodean 8-bit persis sama: Kumpulan byte. Semua byte valid untuk semua pengkodean 8-bit.
Yang terbaik yang dapat Anda harapkan, adalah semacam algoritma yang menganalisis byte, dan berdasarkan probabilitas byte tertentu yang digunakan dalam bahasa tertentu dengan pengkodean tertentu akan menebak apa pengkodean yang digunakan file. Tetapi itu harus mengetahui bahasa mana yang digunakan file tersebut, dan menjadi sama sekali tidak berguna ketika Anda memiliki file dengan penyandian campuran.
Sisi baiknya, jika Anda tahu bahwa teks dalam file ditulis dalam bahasa Inggris, maka Anda tidak akan melihat perbedaan apa pun pengkodean yang Anda putuskan untuk digunakan untuk file itu, karena perbedaan antara semua pengkodean yang disebutkan semuanya dilokalkan di bagian pengkodean yang menentukan karakter yang biasanya tidak digunakan dalam bahasa Inggris. Anda mungkin mengalami beberapa masalah di mana teks menggunakan format khusus, atau versi khusus tanda baca (misalnya CP1252 memiliki beberapa versi karakter kutipan), tetapi untuk inti teks mungkin tidak akan ada masalah.
sumber
Jika Anda dapat mendeteksi setiap encoding KECUALI untuk macroman, maka akan logis untuk mengasumsikan bahwa encoding yang tidak dapat diuraikan ada di macroman. Dengan kata lain, buat saja daftar file yang tidak dapat diproses dan tangani file tersebut seolah-olah file tersebut adalah macroman.
Cara lain untuk mengurutkan file-file ini adalah dengan membuat program berbasis server yang memungkinkan pengguna untuk memutuskan pengkodean mana yang tidak kacau. Tentu saja, ini akan dilakukan di dalam perusahaan, tetapi dengan 100 karyawan melakukan beberapa setiap hari, Anda akan memiliki ribuan file yang diselesaikan dalam waktu singkat.
Akhirnya, bukankah lebih baik hanya mengonversi semua file yang ada ke satu format, dan mengharuskan file baru dalam format itu.
sumber
Saat ini saya sedang menulis program yang menerjemahkan file ke XML. Itu harus mendeteksi otomatis jenis setiap file, yang merupakan superset dari masalah menentukan pengkodean file teks. Untuk menentukan pengkodean saya menggunakan pendekatan Bayesian. Artinya, kode klasifikasi saya menghitung kemungkinan (kemungkinan) bahwa file teks memiliki pengkodean tertentu untuk semua pengkodean yang dipahami. Program kemudian memilih decoder yang paling mungkin. Pendekatan Bayesian bekerja seperti ini untuk setiap pengkodean.
Terungkap bahwa teorema Bayes menjadi sangat mudah dilakukan jika alih-alih menghitung probabilitas, Anda menghitung konten informasi , yang merupakan logaritma dari peluang :
info = log(p / (1.0 - p))
.Anda harus menghitung probabilitas initail priori, dan korelasinya, dengan memeriksa korpus file yang telah Anda klasifikasikan secara manual.
sumber