MacRoman, CP1252, Latin1, UTF-8 ve ASCII arasındaki kodlama nasıl güvenilir bir şekilde tahmin edilir


99

İş yerinde, kodlamayla ilgili bazı çağrışımlar, felaketler veya felaketler olmadan hiçbir hafta geçmiyor gibi görünüyor. Sorun genellikle kodlamayı belirtmeden bir "metin" dosyasını güvenilir bir şekilde işleyebileceklerini düşünen programcılardan kaynaklanır. Ama yapamazsın.

Bu nedenle, dosyaların artık *.txtveya ile biten isimlere sahip olmasının yasaklanmasına karar verildi *.text. Buradaki düşünce, bu uzantıların sıradan programcıyı kodlamalarla ilgili sıkıcı bir gönül rahatlığıyla yanıltmasıdır ve bu da yanlış kullanımlara yol açar. En azından o zaman, çünkü neredeyse hiç yok uzantısı olması daha iyi olurdu biliyorum sen ne var bilmiyorum.

Ancak, o kadar ileri gitmeyeceğiz. Bunun yerine, kodlamayla biten bir dosya adı kullanmanız beklenecektir. Metin dosyaları için Bu nedenle, örneğin, bu gibi bir şey olurdu README.ascii, README.latin1, README.utf8vb

Belirli bir uzantı talep eden dosyalar için, eğer biri Perl veya Python'da olduğu gibi dosyanın kendi içindeki kodlamayı belirleyebiliyorsa, o zaman bunu yapmalısınız. Dosya içinde böyle bir tesisin bulunmadığı Java kaynağı gibi dosyalar için, kodlamayı uzantının önüne koyarsınız, örneğin SomeClass-utf8.java.

Çıktı için UTF-8 şiddetle tercih edilmelidir .

Ancak girdi için, adlı kod tabanımızdaki binlerce dosyayla nasıl başa çıkacağımızı bulmamız gerekiyor *.txt. Yeni standardımıza uyacak şekilde hepsini yeniden adlandırmak istiyoruz. Ama hepsine bakamayız. Yani gerçekten çalışan bir kitaplığa veya programa ihtiyacımız var.

Bunlar çeşitli şekillerde ASCII, ISO-8859-1, UTF-8, Microsoft CP1252 veya Apple MacRoman'da bulunmaktadır. Bir şeyin ASCII olup olmadığını anlayabileceğimizi bilsek de ve bir şeyin muhtemelen UTF-8 olup olmadığını bilmek konusunda iyi bir değişikliğe katlansak da, 8 bitlik kodlamalar konusunda şaşkınız. Çoğu masaüstünün Mac olduğu karma bir Unix ortamında (Solaris, Linux, Darwin) çalıştığımız için, can sıkıcı birkaç MacRoman dosyamız var. Ve bunlar özellikle bir problem.

Bir süredir programlı olarak hangilerinin hangileri olduğunu belirlemenin bir yolunu arıyordum

  1. ASCII
  2. ISO-8859-1
  3. CP1252
  4. MacRoman
  5. UTF-8

bir dosya var ve üç farklı 8-bit kodlamayı güvenilir bir şekilde ayırt edebilecek bir program veya kitaplık bulamadım. Muhtemelen tek başına binden fazla MacRoman dosyamız vardır, bu yüzden hangi karakter seti algılayıcısını kullanırsak kullanalım bunları koklayabilmeli. Baktığım hiçbir şey hileyi yönetemez. Yoğun bakım karakter seti dedektör kitaplığı için büyük umutlarım vardı , ancak MacRoman'ı kaldıramaz. Hem Perl hem de Python'da aynı tür şeyleri yapmak için modüllere de baktım, ama tekrar tekrar aynı hikaye: MacRoman'ı tespit etmek için destek yok.

Bu nedenle aradığım şey, bir dosyanın bu beş kodlamadan hangisinin içinde olduğunu ve tercihen bundan daha fazla olduğunu güvenilir bir şekilde belirleyen mevcut bir kitaplık veya programdır. Özellikle, bahsettiğim üç 3-bit kodlamayı, özellikle de MacRoman'ı ayırt etmek zorundadır . Dosyaların% 99'undan fazlası İngilizce metindir; diğer dillerde birkaç tane var ama çok değil.

Kitaplık koduysa, dil tercihimiz Perl, C, Java veya Python'da ve bu sırayla olmasıdır. Bu sadece bir programsa, tam kaynakta geldiği, Unix üzerinde çalıştığı ve tamamen serbest olduğu sürece hangi dilde olduğu gerçekten umurumuzda değil.

Rastgele kodlanmış milyonlarca eski metin dosyası sorunu olan var mı? Eğer öyleyse, bunu nasıl çözmeye çalıştınız ve ne kadar başarılıydınız? Sorumun en önemli yönü bu, ancak programcıları dosyalarını bu dosyaların içinde bulundukları gerçek kodlamayla adlandırmaya (veya yeniden adlandırmaya) teşvik etmenin, gelecekte bu sorunu önlememize yardımcı olup olmayacağını da merak ediyorum. Hiç kimse bunu kurumsal bir temelde uygulamaya çalıştı mı ve öyleyse bu başarılı oldu mu , başarısız oldu ve neden?

Ve evet, sorunun doğası göz önüne alındığında neden kesin bir cevabı garanti edemeyeceğimi anlıyorum. Bu, özellikle devam etmek için yeterli veriye sahip olmadığınız küçük dosyalarda geçerlidir. Neyse ki, dosyalarımız nadiren küçüktür. Rastgele READMEdosya dışında , çoğu 50k - 250k boyut aralığındadır ve çoğu daha büyüktür. Birkaç K'den büyük herhangi bir şeyin İngilizce olması garanti edilir.

Sorun alanı biyomedikal metin madenciliğidir, bu nedenle bazen PubMedCentral'ın tüm Açık Erişim deposu gibi kapsamlı ve çok büyük şirketlerle uğraşıyoruz. Oldukça büyük bir dosya, 5,7 gigabaytlık BioThesaurus 6.0'dır. Bu dosya özellikle can sıkıcı çünkü neredeyse tamamı UTF-8. Bununla birlikte, bazı kafatasları gitti ve içine 8 bitlik kodlamada olan birkaç satır yapıştırdı — Microsoft CP1252, inanıyorum. Bunun üzerine gitmen epey zaman alıyor. :(


Yanıtlar:


86

İlk olarak, kolay durumlar:

ASCII

Verileriniz 0x7F'nin üzerinde bayt içermiyorsa, ASCII'dir. (Veya 7 bitlik bir ISO646 kodlaması, ancak bunlar çok eski.)

UTF-8

Veri geçerli kılınarak UTF-8 olarak, o zaman güvenli bir şekilde varsayabiliriz Eğer bir UTF-8. UTF-8'in katı doğrulama kuralları nedeniyle, yanlış pozitifler son derece nadirdir.

ISO-8859-1 ile windows-1252 karşılaştırması

Bu iki kodlama arasındaki tek fark, ISO-8859-1'in C1 kontrol karakterlerine sahip olmasıdır, burada windows-1252 yazdırılabilir karakterlere sahiptir € ‚ƒ„… † ‡ ˆ ‰ Š ‹ŒŽ ''“ ”• –—˜ ™ š› œžŸ. Kıvrık tırnaklar veya kısa çizgiler kullanan birçok dosya gördüm, ancak hiçbiri C1 kontrol karakterlerini kullanmıyor. Bu yüzden onlarla veya ISO-8859-1 ile uğraşmayın, bunun yerine sadece windows-1252'yi tespit edin.

Artık size tek bir soru kalıyor.

MacRoman'ı cp1252'den nasıl ayırırsınız?

Bu çok daha yanıltıcı.

Tanımsız karakterler

0x81, 0x8D, 0x8F, 0x90, 0x9D baytları windows-1252'de kullanılmaz. Eğer meydana gelirlerse, verinin MacRoman olduğunu varsayın.

Özdeş karakterler

0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ) baytları her iki kodlamada da aynıdır. Bunlar yalnızca ASCII olmayan baytlarsa, MacRoman'ı veya cp1252'yi seçmeniz önemli değildir.

İstatistiksel yaklaşım

UTF-8 olduğunu bildiğiniz verilerdeki karakter frekanslarını (bayt DEĞİL!) Sayın. En sık kullanılan karakterleri belirleyin. Ardından, cp1252 veya MacRoman karakterlerinin daha yaygın olup olmadığını belirlemek için bu verileri kullanın.

Örneğin, rastgele 100 İngilizce Wikipedia makalesi üzerinde gerçekleştirdiğim bir araştırmada, en yaygın ASCII olmayan karakterler ·•–é°®’èö—. Bu gerçeğe dayanarak,

  • Baytlar 0x92, 0x95, 0x96, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9 veya 0xF6, windows-1252'yi önerir.
  • 0x8E, 0x8F, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5 veya 0xE1 baytları MacRoman'ı önerir.

Cp1252'yi öneren baytları ve MacRoman'ı öneren baytları sayın ve hangisinin en büyük olduğunu seçin.


6
Cevabınızı kabul ettim çünkü daha iyisi kendini göstermedi ve benim üzerinde uğraştığım konuları yazarken iyi bir iş çıkardınız. Benim bulduğum sayının yaklaşık iki katı olmasına rağmen, gerçekten de bu baytları yok edecek programlarım var.
tchrist

10
Sonunda bunu uygulamaya başladım. Wikipedia'nın iyi bir eğitim verisi olmadığı ortaya çıktı. LANGUAGES bölümünü saymadan 1k rastgele en.wikipedia makalesinden, 50.000 unASCII kod noktası aldım, ancak dağıtım güvenilir değil: orta nokta ve madde işareti çok yüksek ve c & c & c. Bu yüzden tüm UTF8 PubMed Açık Erişim külliyatını, madencilik + 14M unASCII kod noktalarını kullandım. Bunları, tüm 8 bit kodlamaların göreli frekans modelini oluşturmak için kullanıyorum, sizinkinden daha güzel ama bu fikre dayanarak. Bu , hedef alan olan biyomedikal metinler için kodlamanın oldukça öngörücü olduğunu kanıtlıyor . Bunu yayınlamalıyım. Teşekkürler!
tchrist

5
Hala MacRoman dosyam yok, ancak satır sınırlayıcıları yararlı bir test olarak CR'nin kullanılması olmaz. Bu, OS9 hakkında bir bilgim olmasa da, Mac OS'nin eski sürümleri için işe yarar.
Milliways

10

Daha fazla belge şurada bulunabilir: mozilla.org/projects/intl/detectorsrc.html , buradan , belgelerin içine bakarsanız desteklenen karakter kümelerini bulabileceğiniz anlamına gelir
Joel Berger

@Joel: Kaynağa girdim. Retorik bir soruydu. x-mac-cyrillicdestekleniyor, x-mac-hebrewyorumlarda uzun uzun tartışılıyor, x-mac-anything-elsebahsedilmiyor.
John Machin

@John Machin: Kiril ve İbranice'nin başını sallaması garip, ama başka bir şey yok. Sadece başka bir dokümantasyon kaynağına atıyordum, daha fazla okumamıştım, bunu yaptığın için teşekkürler!
Joel Berger

7

Böyle bir buluşsal yöntem denemem (ASCII ve UTF-8'i dışladığınızı varsayarak):

  • 0x7f ila 0x9f hiç görünmüyorsa, muhtemelen ISO-8859-1'dir, çünkü bunlar çok nadiren kullanılan kontrol kodlarıdır.
  • 0x91'den 0x94'e kadar görünüyorsa, büyük olasılıkla Windows-1252'dir, çünkü bunlar "akıllı tırnaklardır", bu aralıktaki İngilizce metinde kullanılan en olası karakterler açık arayla. Daha kesin olmak için çiftler arayabilirsin.
  • Aksi takdirde, MacRoman'dır, özellikle 0xd2'den 0xd5'e kadar çok şey görüyorsanız (burası tipografik alıntıların MacRoman'da olduğu yerdir).

Kenar notu:

Dosya içinde böyle bir tesisin bulunmadığı Java kaynağı gibi dosyalar için, kodlamayı SomeClass-utf8.java gibi uzantının önüne koyarsınız.

Bunu yapma!!

Java derleyicisi, dosya adlarının sınıf adlarıyla eşleşmesini bekler, bu nedenle dosyaların yeniden adlandırılması kaynak kodunu derlenemez hale getirir. Doğru olan, kodlamayı tahmin etmek ve ardından native2asciiaracı kullanarak ASCII olmayan tüm karakterleri Unicode kaçış dizilerine dönüştürmek olacaktır .


7
Stoopid kompilor! Hayır, insanlara yalnızca ASCII kullanabileceklerini söyleyemeyiz; bu artık 1960'lar değil. Kaynağın belirli bir kodlamada olduğu gerçeğinin kaynak kodun dışında saklanmaya zorlanmaması için bir @ kodlama ek açıklaması olsaydı sorun olmazdı, Java'nın ne Perl ne de Python'da muzdarip olmadığı gerçekten aptalca bir eksikliktir. . Kaynakta olmalı. Yine de asıl sorunumuz bu değil; 1000'lerce dosyadır *.text.
tchrist

3
@tchrist: Aslında böyle bir açıklamayı desteklemek için kendi açıklama işlemcinizi yazmak o kadar da zor olmaz. Yine de standart API'de olmaması utanç verici bir gözetim.
Michael Borgwardt

Java @ kodlamayı desteklese bile, bu kodlama bildiriminin doğru olmasını sağlamaz .
dan04

4
@ dan04: XML, HTML veya başka herhangi bir yerdeki kodlama bildirimi için aynı şeyi söyleyebilirsiniz. Ancak bu örneklerde olduğu gibi, Standart API'de tanımlanmış olsaydı, kaynak kodla çalışan çoğu araç (özellikle editörler ve IDE'ler) onu destekler ve bu da insanların yanlışlıkla içeriği 'kodlaması eşleşmeyen dosyaları oluşturmasını oldukça güvenilir bir şekilde engellerdi. beyan.
Michael Borgwardt

4
"Java derleyicisi dosya adlarının sınıf adlarıyla eşleşmesini bekler." Bu kural, yalnızca dosya üst düzey bir genel sınıfı tanımladığında geçerlidir.
Matthew Flaschen

6

"Perl, C, Java veya Python ve bu sırayla": ilginç tutum :-)

"Bir şeyin muhtemelen UTF-8 olup olmadığını bilmede iyi bir değişikliğe sahibiz": Aslında, UTF-8'in kaybolacak kadar küçük olması nedeniyle, yüksek bit kümeli baytlar kullanan başka bir karakter kümesinde kodlanmış anlamlı metin içeren bir dosyanın başarıyla kod çözme şansı.

UTF-8 stratejileri (en az tercih edilen dilde):

# 100% Unicode-standard-compliant UTF-8
def utf8_strict(text):
    try:
        text.decode('utf8')
        return True
    except UnicodeDecodeError:
        return False

# looking for almost all UTF-8 with some junk
def utf8_replace(text):
    utext = text.decode('utf8', 'replace')
    dodgy_count = utext.count(u'\uFFFD') 
    return dodgy_count, utext
    # further action depends on how large dodgy_count / float(len(utext)) is

# checking for UTF-8 structure but non-compliant
# e.g. encoded surrogates, not minimal length, more than 4 bytes:
# Can be done with a regex, if you need it

Bunun ASCII veya UTF-8 olmadığına karar verdiğinizde:

Bildiğim Mozilla kökenli karakter seti detektörleri MacRoman'ı desteklemiyor ve her halükarda özellikle İngilizce ile 8 bitlik karakter setlerinde iyi bir iş çıkarmıyor çünkü AFAICT verilen kod çözmenin mantıklı olup olmadığını kontrol etmeye bağlılar. dil, noktalama karakterlerini göz ardı ederek ve o dildeki geniş bir belge yelpazesine dayanır.

Diğerlerinin de belirttiği gibi, cp1252 ve macroman arasında ayrım yapmak için gerçekten sadece yüksek bit setli noktalama karakterlerine sahipsiniz. Shakespeare veya Hansard veya KJV Bible değil, kendi belgeleriniz üzerinde Mozilla tipi bir model eğitmenizi ve 256 baytı hesaba katmanızı öneririm. Dosyalarınızın içinde işaretleme (HTML, XML, vb.) Bulunmadığını varsayıyorum - bu, şok edici bir şey olasılığını bozabilir.

Çoğunlukla UTF-8 olan ancak kodu çözülemeyen dosyalardan bahsettiniz. Şunlardan da çok şüphelenmelisiniz:

(1) ISO-8859-1 ile kodlandığı iddia edilen ancak 0x80 ila 0x9F aralığında "kontrol karakterleri" içeren dosyalar ... Bu o kadar yaygındır ki taslak HTML5 standardı ISO-8859 olarak bildirilen TÜM HTML akışlarının kodunu çözmeyi söyler -1 cp1252 kullanarak.

(2) OK kodunu UTF-8 olarak çözen dosyalar, ancak ortaya çıkan Unicode U + 0080 ile U + 009F arasında "kontrol karakterleri" içerir ... bu, cp1252 / cp850'nin dönüştürülmesinden kaynaklanabilir (görüldü!) / Etc dosyaları "ISO-8859-1" den UTF-8'e.

Arka plan: Dosya odaklı (web odaklı yerine) legacy ** nve cp850 ve cp437 gibi 8 bitlik karakter kümeleriyle iyi çalışan Python tabanlı bir karakter kümesi algılayıcısı oluşturmak için ıslak Pazar öğleden sonra bir projem var. Henüz prime time yakın bir yerde değil. Eğitim dosyalarıyla ilgileniyorum; ISO-8859-1 / cp1252 / MacRoman dosyalarınız, herhangi birinin kod çözümünün olmasını beklediğiniz kadar "ipoteksiz" mi?


1
dil sıralamasının nedeni ortamdır. Başlıca uygulamalarımızın çoğu java ve küçük yardımcı programlarda olma eğilimindedir ve bazı uygulamalar perl'dedir. Python'da burada ve orada olan küçük bir kodumuz var. Çoğunlukla bir C ve perl programcısıyım, en azından ilk tercihim, bu yüzden ya uygulama kitaplığımıza eklemek için bir java çözümü ya da bunun için bir perl kitaplığı arıyordum. Eğer C ise, perl arayüzüne bağlamak için bir XS yapıştırıcı katmanı oluşturabilirdim, ancak bunu daha önce python'da yapmadım.
tchrist

3

Sizin de keşfetmiş olduğunuz gibi, bu sorunu çözmenin mükemmel bir yolu yoktur, çünkü bir dosyanın hangi kodlamayı kullandığına dair örtük bilgi olmadan, tüm 8 bit kodlamalar tamamen aynıdır: Bir bayt koleksiyonu. Tüm baytlar, tüm 8 bit kodlamalar için geçerlidir.

Umut edebileceğiniz en iyi şey, baytları analiz eden ve belirli bir baytın belirli bir dilde belirli bir kodlamayla kullanılma olasılıklarına dayalı olarak, dosyaların hangi kodlamayı kullandığını tahmin eden bir tür algoritmadır. Ancak bu, dosyanın hangi dili kullandığını bilmek zorundadır ve karışık kodlamalı dosyalarınız olduğunda tamamen yararsız hale gelir.

Tersine, bir dosyadaki metnin İngilizce yazılmış olduğunu biliyorsanız, o dosya için hangi kodlamayı kullanmaya karar verirseniz verin, bahsedilen tüm kodlamalar arasındaki farkların tümü kodlamaların normalde İngilizce dilinde kullanılmayan karakterleri belirten bölümleri. Metnin özel biçimlendirmeyi veya özel noktalama işaretlerini kullandığı durumlarda bazı sorunlar yaşayabilirsiniz (örneğin CP1252, alıntı karakterlerinin birkaç versiyonuna sahiptir), ancak metnin özü için muhtemelen hiçbir sorun olmayacaktır.


1

Macroman HARİÇ her kodlamayı tespit edebilirseniz, deşifre edilemeyenlerin macroman'da olduğunu varsaymak mantıklı olacaktır. Başka bir deyişle, işlenemeyen dosyaların bir listesini yapın ve bunları makroman gibi ele alın.

Bu dosyaları sıralamanın başka bir yolu da, kullanıcıların hangi kodlamanın bozuk olmadığına karar vermelerine olanak tanıyan sunucu tabanlı bir program yapmaktır. Tabii ki, şirket içinde olacaktır, ancak 100 çalışan her gün birkaç iş yaptığında, hiçbir zaman binlerce dosya hazırlamış olacaksınız.

Son olarak, mevcut tüm dosyaları tek bir formata dönüştürmek ve yeni dosyaların bu formatta olmasını gerektirmek daha iyi olmaz mıydı.


5
Komik! 30 dakika kesintiye uğradıktan sonra bu yorumu ilk okuduğumda, "macroman" ı "makro adam" olarak okudum ve OP'nin bundan bahsedip bahsetmediğini görmek için bu dizeyi aramaya kadar MacRoman ile bağlantı kurmadım.
Adrian Pronk

+1 bu cevap biraz ilginç. iyi mi kötü mü olduğundan emin değilim. Fark edilmeyebilecek mevcut bir kodlamayı düşünen var mı? gelecekte olması muhtemel mi?
kullanıcı adı

1

Rastgele kodlanmış milyonlarca eski metin dosyası sorunu olan var mı? Eğer öyleyse, bunu nasıl çözmeye çalıştınız ve ne kadar başarılıydınız?

Şu anda dosyaları XML'e çeviren bir program yazıyorum. Bir metin dosyasının kodlamasını belirleme sorununun üst kümesi olan her dosyanın türünü otomatik olarak algılaması gerekir. Kodlamayı belirlemek için Bayesci bir yaklaşım kullanıyorum. Yani, sınıflandırma kodum, bir metin dosyasının anladığı tüm kodlamalar için belirli bir kodlamaya sahip olma olasılığını (olasılığını) hesaplar. Program daha sonra en olası kod çözücüyü seçer. Bayes yaklaşımı, her kodlama için bu şekilde çalışır.

  1. Her kodlamanın frekanslarına bağlı olarak, dosyanın kodlamada olduğu ilk ( önceki ) olasılığı ayarlayın .
  2. Sırayla dosyadaki her baytı inceleyin. Mevcut olan bayt değeri ile gerçekte bu kodlamada bulunan dosya arasındaki ilişkiyi belirlemek için bayt değerini arayın. Yeni (hesaplamak için bu korelasyon kullanın arka dosya kodlamasında olduğu) olasılık. İncelenecek daha fazla baytınız varsa, sonraki baytı incelerken bu baytın son olasılığını önceki olasılık olarak kullanın.
  3. Dosyanın sonuna geldiğinizde (aslında sadece ilk 1024 bayta bakıyorum), sahip olduğunuz olasılık, dosyanın kodlamada olma olasılığıdır.

Bu Bayes teoremi haline gelir transpires çok yerine olasılıkları hesaplama, sen hesaplamak eğer yapmak kolay bilgi içeriği logaritması olan, oran : info = log(p / (1.0 - p)).

Başlangıçtaki öncelik olasılığını ve korelasyonları manuel olarak sınıflandırdığınız bir dosya topluluğunu inceleyerek hesaplamanız gerekecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.