UTF-16 zararlı olarak kabul edilmeli mi?


432

Muhtemelen tartışmalı bir sorunun ne olduğunu soracağım: “En popüler kodlamalardan biri olan UTF-16 zararlı olarak kabul edilmeli mi?”

Bu soruyu neden soruyorum?

Kaç programcı UTF-16'nın gerçekten değişken uzunluklu bir kodlama olduğunun farkında? Bununla, vekil çiftler olarak temsil edilen, birden fazla element alan kod noktaları olduğunu kastediyorum.

Biliyorum; Java, String, C # 's String, Win32 API, Qt GUI kütüphaneleri, ICU Unicode kütüphanesi, vb. gibi pek çok uygulama, çerçeve ve API kullanılır. BMP dışındaki karakterlerin listesi (iki UTF-16 öğesi kullanılarak kodlanması gereken karakterler).

Örneğin, şu karakterlerden birini düzenlemeyi deneyin:

  • 𝄞 ( U + 1D11E ) MÜZİKSEL SEMBOL G CLEF
  • 𝕥 ( U + 1D565 ) MATEMATİKSEL ÇİFT KİŞİLİK KÜÇÜK T
  • 𝟶 ( U + 1D7F6 ) MATEMATİKSEL MONOSPACE DIGIT ZERO
  • 𠂊 ( U + 2008A ) Han Karakteri

Yüklediğiniz yazı tipine bağlı olarak bazılarını kaçırabilirsiniz. Bu karakterlerin tümü BMP'nin (Temel Çok Dilli Düzlem) dışındadır. Bu karakterleri göremiyorsanız, onlara Unicode Karakter referansında bakmayı da deneyebilirsiniz .

Örneğin, Windows'ta bu karakterleri içeren dosya adları oluşturmaya çalışın; UTF-16 kullanan farklı uygulamalarda nasıl davrandıklarını görmek için bu karakterleri "geri al" ile silmeyi deneyin. Bazı testler yaptım ve sonuçlar oldukça kötü:

  • Opera’nın düzenleme konusunda problemi var (geri silme işleminde gerekli 2 baskıyı silin)
  • Not defteri onlarla doğru şekilde baş edemez (silme işlemi için gerekli 2 basışı silin)
  • Pencere diyaloglarında bozuk dosya isimleri bozuk (geri silme işleminde 2 basma gerekli)
  • Tüm QT3 uygulamaları onlarla başa çıkamaz - bir sembol yerine iki boş kareyi gösterin .
  • Python u'X'!=unicode('X','utf-16'), X BMP dışında bir karakterde olduğunda doğrudan bazı platformlarda kullanıldığında bu karakterleri yanlış kodlar .
  • Python 2.5 unicodedata, python UTF-16 Unicode dizeleriyle derlendiğinde bu tür karakterlerde özellik alamaz.
  • StackOverflow, doğrudan Unicode karakterleri olarak düzenlenmişse bu karakterleri metinden kaldırıyor gibi görünmektedir (bu karakterler HTML Unicode çıkışları kullanılarak gösterilmiştir).
  • WinForms TextBox, MaxLength ile sınırlı olduğunda geçersiz dize oluşturabilir .

UTF-16 kullanan birçok uygulamada bu tür hataların bulunması son derece kolaydır.

Öyleyse ... UTF-16'nın zararlı olarak kabul edilmesi gerektiğini düşünüyor musunuz?


64
Gerçekten doğru değil. "שָׁ", "ש" ve "ׁ", "ש", "ׁ" ve "ש" karakterlerini içeren bileşik karakterleri "if" yazarsanız, o zaman her birinin çıkarılması mantıklıdır, tuşuna bastığınızda bir kod noktasını kaldırırsınız " geri al ve "del" e bastığınızda voveller dahil tüm karakterleri kaldır. Ancak, asla yasa dışı metin durumu - yasadışı kod noktaları üretmezsiniz . Bu nedenle, geri tuşuna bastığınızda ve metinde yasa dışı aldığınızda durum yanlıştır.

41
CiscoIPPhone: Eğer bir hata "birçok kez farklı insanlar tarafından birkaç kez bildirilirse", ve birkaç yıl sonra bir geliştirici, "İster inanın ister inanmayın, davranışın çoğunlukla kasıtlı olduğunu" yazan bir dev blogunda yazar. hafifçe) Muhtemelen şimdiye kadar verilmiş en iyi tasarım kararı olmadığını düşünüyorum. :-) Sadece kasıtlı olması, böcek olmadığı anlamına gelmez.

145
Harika yazı. UTF-16 aslında "her iki dünyanın da en kötüsü" dür: UTF8 değişken uzunlukludur, Unicode'un tamamını kapsar, ham kod noktalarına ve ham kod noktalarından bir dönüşüm algoritması gerektirir, ASCII ile sınırlıdır ve endianness sorunu yoktur. UTF32 sabit uzunluklu, dönüşüm gerektirmiyor, ancak daha fazla yer kaplıyor ve endianness sorunları var. Şimdiye kadar çok iyi, UTF32'yi dahili olarak ve UTF8'i serileştirme için kullanabilirsiniz. Fakat UTF16'nın faydası yok: Endian bağımlı, değişken uzunluklu, çok fazla alan kaplıyor, ASCII uyumlu değil. UTF16 ile düzgün şekilde başa çıkmak için gereken çaba UTF8'de daha iyi harcanabilir.
Kerrek SB,

26
@Ian: UTF-8 UTF-8 ile aynı uyarılara sahip DEĞİLDİR . UTF-8'de vekiller olamaz. UTF-8, olmadığı bir şey olarak maskelenmez, ancak UTF-16'yı kullanan çoğu programcı yanlış kullanıyor. Biliyorum. Onları tekrar tekrar, tekrar tekrar izledim.
tchrist

18
Ayrıca, UTF-8'in sorunu da yok çünkü herkes bunu değişken genişlikli bir kodlama olarak kabul ediyor. UTF-16'nın probleminin sebebi, herkesin kendisine sabit genişlikli bir kodlama gibi davranmasıdır.
Christoffer Hammarström

Yanıtlar:


340

Bu eski bir cevap. En son güncellemeler için UTF-8 Her Yerde
bölümüne bakınız .

Görüş: Evet, UTF-16 zararlı olarak kabul edilmelidir . Varlığının nedeni, bir süre önce, Widechar'ın şu anda UCS-4'ün olduğu gibi olacağı yönündeki yanlış bir inancı olduğu içindi.

UTF-8'in “merkez-merkezciliği” ne rağmen, metin için tek yararlı kodlama düşünülmelidir. Program kaynak kodlarının, web sayfalarının ve XML dosyalarının, işletim sistemi dosya adlarının ve diğer bilgisayardan bilgisayara metin arayüzlerinin asla bulunmaması gerektiği iddia edilebilir. Ancak yaptıklarında, metin yalnızca insan okuyucular için değildir.

Öte yandan, UTF-8 ek yükü, önemli avantajlara sahipken ödenmesi gereken küçük bir fiyattır. Dizeleri geçiren habersiz kodla uyumluluk gibi avantajlar char*. Bu harika bir şey. UTF-16’da SHORTER olan UTF-8’de olduğundan daha az kullanışlı karakter var.

Diğer tüm kodlamaların sonunda öleceğine inanıyorum. Bu, MS-Windows, Java, ICU, python'un favorileri olarak kullanmayı bırakmasını içerir. Uzun araştırma ve tartışmaların ardından şirketimdeki geliştirme sözleşmeleri, OS API çağrıları dışında her yerde UTF-16 kullanılmasını yasakladı ve bu, uygulamalarımızdaki performansın önemine ve Windows kullanmamıza rağmen. Dönüşüm işlevleri, her zaman varsayılan UTF8'leri std::string, Windows'un kendisinin düzgün bir şekilde desteklemediği yerel UTF-16'ya dönüştürmek için geliştirilmiştir .

" İhtiyaç duyulan şeyi kullanın " diyenlere şunu söylüyorum: aynı kodlamayı her yerde kullanmanın çok büyük bir avantajı var, aksi halde yapmak için yeterli neden göremiyorum. Özellikle, wchar_tC ++ 'a eklemenin bir hata olduğunu ve Unicode' un C ++ 0x 'a eklendiğini düşünüyorum . STL uygulamalarından talep edilmesi gereken, ancak her std::stringveya char*parametrenin unicode uyumlu olarak kabul edilmesi gerektiğidir.

Ben de " ne istersen onu kullan " yaklaşımına karşıyım . Böyle bir özgürlük için sebep göremiyorum. Metin konusunda yeterince karışıklık var ve bu kırık yazılımlar ortaya çıkıyor. Yukarıda belirtildiği gibi, programcıların nihayet UTF-8'deki fikir birliğine varması gerektiğine ikna oldum. (İyi konuşmayan bir ülkeden geliyorum ve Windows'ta büyüdüm, bu yüzden en son UTF-16'ya dini gerekçelerle saldırması bekleniyor.)

Windows'ta metin nasıl yaptığım ve derleme zamanı denetimli unicode doğruluğu, kullanım kolaylığı ve kodun daha iyi çoklu platform özelliği için herkese önerdiklerim hakkında daha fazla bilgi paylaşmak istiyorum. Öneri, pencerelerde Unicode kullanmanın doğru yolu olarak genellikle önerilenlerden önemli ölçüde farklıdır. Ancak, bu önerilerin derinlemesine araştırılması aynı sonucu verdi. Yani işte gidiyor:

  • UTF-16'yı kabul eden API'lerin bitişik noktalarından başka bir yerde kullanmayın wchar_tveya kullanmayın std::wstring.
  • Kullanmayın _T("")veya L""UTF-16 değişmezleri (Bunlar IMO’nun UTF-16 itirazının bir parçası olarak standart dışı bırakılması gerekir).
  • Tipleri, fonksiyonları ya da duyarlı onların türevleri kullanmayınız _UNICODEgibi sabit, LPTSTRya da CreateWindow().
  • Yine de, _UNICODEher zaman tanımlanmış, char*dizelerin WinAPI'ye iletilmesinden kaçınmak için sessizce derlenmeden
  • std::stringsve char*programın herhangi bir yerinde UTF-8 olarak kabul edilir (aksi belirtilmezse)
  • Tüm dizelerim, std::stringchar * veya string değişmezine geçebildiğiniz halde convert(const std::string &).
  • sadece widechars ( LPWSTR) işlevini kullanan Win32 işlevlerini kullanın . Asla kabul edenler LPTSTRveya LPSTR. Parametreleri bu şekilde geçirin:

    ::SetWindowTextW(Utils::convert(someStdString or "string litteral").c_str())
    

    (Politika aşağıdaki dönüşüm işlevlerini kullanır.)

  • MFC dizeleriyle:

    CString someoneElse; // something that arrived from MFC. Converted as soon as possible, before passing any further away from the API call:
    
    std::string s = str(boost::format("Hello %s\n") % Convert(someoneElse));
    AfxMessageBox(MfcUtils::Convert(s), _T("Error"), MB_OK);
    
  • Windows'ta dosya, dosya adı ve fstream ile çalışmak:

    • Argümanları asla aileye iletmeyin std::stringveya vermeyin . MSVC STL UTF-8 argümanlarını desteklemez, ancak aşağıdaki gibi kullanılması gereken standart olmayan bir uzantıya sahiptir:const char*fstream
    • std::stringArgümanları std::wstringşununla dönüştür Utils::Convert:

      std::ifstream ifs(Utils::Convert("hello"),
                        std::ios_base::in |
                        std::ios_base::binary);
      

      MSVC'nin tutumu fstreamdeğiştiğinde , el ile kaldırmamız gerekir .

    • Bu kod çok platformlu değildir ve gelecekte manuel olarak değiştirilmesi gerekebilir
    • Daha fstreamfazla bilgi için bkz. Unicode araştırma / tartışma durumu 4215
    • Asla UTF8 olmayan içeriğe sahip metin çıktı dosyaları üretme
    • fopen()RAII / OOD nedenleriyle kullanmaktan kaçının . Gerekirse, _wfopen()yukarıdaki ve WinAPI kurallarını kullanın .

// For interface to win32 API functions
std::string convert(const std::wstring& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

std::wstring convert(const std::string& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

// Interface to MFC
std::string convert(const CString &mfcString)
{
#ifdef UNICODE
    return Utils::convert(std::wstring(mfcString.GetString()));
#else
    return mfcString.GetString();   // This branch is deprecated.
#endif
}

CString convert(const std::string &s)
{
#ifdef UNICODE
    return CString(Utils::convert(s).c_str());
#else
    Exceptions::Assert(false, "Unicode policy violation. See W569"); // This branch is deprecated as it does not support unicode
    return s.c_str();   
#endif
}

39
Katılıyorum Utf16'nın pek çok Asya dili için utf8'e göre avantajları, belirlediğiniz noktalara tamamen hakimdir. Japonların, Tayland'ın, Çin'in, vb. Bu kodlamayı bırakacağını ummak saf değildir. Karakter setleri arasındaki sorunlu çatışmalar, karakter karakterleri farklılıklar dışında çoğunlukla benzer göründüğü zamandır. Standart hale getirmeyi öneriyorum: sabit 7 bit: iso-irv-170; 8bit değişken: utf8; 16bit değişken: utf16; 32bit sabit: ucs4.

82
@Charles: girişiniz için teşekkürler. Doğru, bazı BMP karakterleri UTF-8’de UTF-16’dan daha uzun Ancak, bununla yüzleşelim: sorun BMP'nin Çince karakterlerinin aldığı baytlarda değil, ortaya çıkan yazılım tasarım karmaşıklığındadır. Bir Çinli programcının yine de değişken uzunluktaki karakterleri tasarlaması gerekiyorsa, UTF-8'in sistemdeki diğer değişkenlerle karşılaştırıldığında hala küçük bir bedel olduğu görülüyor. Alan çok önemliyse UTF-16'yı bir sıkıştırma algoritması olarak kullanabilir, ancak o zaman bile LZ ile eşleşmez ve LZ veya diğer genel sıkıştırma sonrasında aynı boyut ve entropi alır.

32
Temel olarak söylediğim şey, mevcut char * programlarıyla da uyumlu olan ve aynı zamanda bugün her şey için en popüler olan One kodlaması ile sunulan basitleştirmenin. Neredeyse eski güzel "düz metin" günlerde olduğu gibidir. Adı olan bir dosyayı açmak ister misiniz? Ne tür bir unicode, vb. Yaptığınıza bakmanıza gerek yok. Biz geliştiricilere, UTF-16'yı çok özel bir ciddi optimizasyon durumuyla sınırlandırıyoruz;

17
UTF-8'i dahili olarak kullanmayı seçerken Linux'un özel bir ihtiyacı vardı: Unix ile uyumluluk. Windows buna ihtiyaç duymadı ve böylece geliştiriciler Unicode'u uyguladıklarında, metni işleyen hemen hemen tüm fonksiyonların UCS-2 sürümlerini eklediler ve çok baytlıları basitçe UCS-2'ye çevirip diğerlerini çağırdılar. Daha sonra UCS-2'yi UTF-16 ile değiştirir. Öte yandan Linux 8 bitlik kodlamaya devam etti ve bu nedenle UTF-8'i kullandı.
Mircea Chirea

34
@Pavel Radzivilovsky: BTW, "Diğer tüm kodlamaların sonunda öleceğine inanıyorum. Bu, MS-Windows, Java, ICU, python'un favori olarak kullanmayı bırakmasını içerir." ve "Özellikle, wchar_t'yi C ++ 'a eklemenin bir hata olduğunu düşünüyorum, bu yüzden C ++ Ox'a unicode eklemeleri de var." ya oldukça saf ya da çok kibirli. Bu da evde Linux ile kodlayan ve UTF-8 karakterlerinden memnun olan birinden geliyor. Açıkça söylemek gerekirse: O olmayacak .
paercebal,

157

Unicode kod noktaları karakter değildir! Bazen onlar bile glif değildir (görsel formlar).

Bazı örnekler:

  • "Ⅲ" gibi Romen rakamıyla kod noktaları. ("İii" gibi görünen tek bir karakter.)
  • Tek bir birleşik karakter "\ u00e1" veya bir karakterle ayrılmış ve "diacritic" \ u0061 \ u0301 "karakterlerinden oluşan" á "gibi aksanlı karakterler.
  • Yunanca küçük harf sigma gibi karakterlerin ortası ("σ") ve sonu ("ς") için farklı biçimlerde olan ancak arama için eşanlamlı olması gereken karakterler.
  • İçeriğe bağlı olarak ve anlamsal arama için göz ardı edilen, görsel olarak görüntülenebilecek veya gösterilemeyen Unicode isteğe bağlı tire U + 00AD.

Unicode düzenlemeyi doğru yapmanın tek yolu, bir uzman tarafından yazılmış bir kütüphane kullanmak veya bir uzman olmak ve kendiniz yazmaktır. Eğer sadece kod noktaları sayıyorsanız, günah halinde yaşıyorsunuz demektir.


19
Bu. Bu çok fazla. UTF-16 sorunlara neden olabilir, ancak UTF-32'yi kullanmak bile size sorun yaratabilir (ve verecek).
bcat

11
Karakter nedir Bir kod noktasını karakter olarak tanımlayabilir ve hemen hemen her şey yolunda gidebilirsiniz. Kullanıcı tarafından görülebilen bir glifi kastediyorsanız, bu başka bir şey.
tchrist

7
@tchrist bu tanımı iyi, ancak başka bir şey için alan ayırmak için emin? Çok değil. Bir birleştirme karakterini tek bir karakter olarak ele alırsanız (yani, bir silme veya "ilk N karakterini al" işlemi için) garip ve yanlış davranışlarla karşılaşırsınız. Bir kod noktası yalnızca en az bir başkasıyla birleştirildiğinde anlam kazanıyorsa, bunu mantıklı bir şekilde kendi başınıza kaldıramazsınız.
Voo

6
@Pererier, bu partiye geç kaldı, ama bu konuda yorum yapmak zorundayım. Bazı diller, çok büyük miktarda diakritik kombinasyon setine sahiptir (Vietnamca, yani, mệt đừ). Aksan başına bir karakter yerine kombinasyonlara sahip olmak çok yararlıdır.
Asthasr,

21
terminoloji üzerinde küçük bir not: codepoints do karşılık unicode karakterleri ; Daniel'in burada bahsettiği şey , unicode grapheme kümelerine karşılık gelen, kullanıcı tarafından algılanan karakterlerdir
Christoph

54

Hangi Unicode Dönüşüm Formunun (UTF) ne kullanılacağına dair basit bir kural vardır: - depolama ve iletişim için utf-8 - veri işleme için utf-16 - kullandığınız platform API'sının çoğu ise utf-32 ile gidebilirsiniz utf-32 (UNIX dünyasında yaygın).

Günümüzde çoğu sistem utf-16'yı kullanır (Windows, Mac OS, Java, .NET, ICU, Qt). Ayrıca bu belgeye bakın: http://unicode.org/notes/tn12/

"Zararlı olarak UTF-16" ya dönersek diyeceğim: kesinlikle hayır.

Vekillerden korkan insanlar (Unicode'u değişken uzunluktaki bir kodlamaya dönüştürdüklerini düşünerek), karakterlerle eşleştirmeyi Unicode kod noktası haline getiren diğer (çok daha büyük) karmaşıklıkları anlamıyorlar: karakterleri, bitişik harfleri, varyasyon seçicileri birleştirme , kontrol karakterleri vb.

Sadece bu diziyi burada okuyun http://www.siao2.com/2009/06/29/9800913.aspx ve UTF-16'nın nasıl kolay bir problem haline geldiğini görün.


26
Lütfen UNIX dünyasında UTF-32'nin yaygın olduğu bazı örnekler ekleyin!
maxschlepzig

48
Hayır, veri işleme için UTF-16'yı kullanmak istemezsiniz. Kıçındaki bir acı. UTF-8'in tüm dezavantajlarına sahiptir ancak avantajlarından hiçbiri yoktur. Hem UTF-8 hem de UTF-32, daha önce Bayan UTF-16 olarak bilinen ve daha önce kızlık soyadı UCS-2 olan kısır saldırıya göre daha üstün.
tchrist

34
Dün Java çekirdeği String sınıfının equalsIgnoreCaseyönteminde (dize sınıfındaki diğerleri de) Java'nın UTF-8 ya da UTF-32 kullandığı bir hatayı buldum . UTF-16'yı kullanan herhangi bir kodda milyonlarca uyuyan bomba kabuğu var ve onlardan bıktım ve yoruldum. UTF-16, yazılımımızı sonsuza dek sonsuza dek sinsi böceklere boğan kısır bir suçtur. Açıkça zararlıdır ve itiraz edilmeli ve yasaklanmalıdır.
tchrist

7
tchrist Vay bu yüzden vekil olmayan bir farkındalık işlevi (hiçbiri varken yazıldığından ve ne yazık ki uyarlanmayı imkansız kılacak şekilde belgelendirildiğinden yazılmıştır - çünkü .toUpperCase (char) yanlış davranışla sonuçlanacaktır? Eski bir kod noktası haritasına sahip bir UTF-32 fonksiyonunun bunu daha iyi idare edemeyeceğini biliyorsunuz? Ayrıca tüm Java API tanıtıcıları özellikle iyi değil ve Unicode ile ilgili daha karmaşık noktaların hiç de değil - ve daha sonra kullanılan kodlama hiç önemli olmaz.
Voo

8
-1: .Substring(1).NET'te koşulsuz bir durum , BMP olmayan tüm Unicode'lar için desteği bozan bir şeyin önemsiz bir örneğidir. UTF-16'yı kullanan her şeyde bu sorun var; sabit genişlikli bir kodlama olarak değerlendirmek çok kolaydır ve sorunları nadiren görürsünüz. Unicode'u desteklemek istiyorsanız, bu aktif olarak zararlı bir kodlama yapar.
Roman Starkov

43

Evet kesinlikle.

Neden? Egzersiz kodu ile ilgili olmalı .

Bu kod noktası kullanım istatistiklerine Tom Christiansen'in büyük bir kurumunda bakarsanız, trans-8bit BMP kod noktalarının, BMP olmayan kod noktalarından daha büyükse birkaç sıra kullanıldığını göreceksiniz:

 2663710 U+002013 ‹–›  GC=Pd    EN DASH
 1065594 U+0000A0 ‹ ›  GC=Zs    NO-BREAK SPACE
 1009762 U+0000B1 ‹±›  GC=Sm    PLUS-MINUS SIGN
  784139 U+002212 ‹−›  GC=Sm    MINUS SIGN
  602377 U+002003 ‹ ›  GC=Zs    EM SPACE

 544 U+01D49E ‹𝒞›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL C
 450 U+01D4AF ‹𝒯›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL T
 385 U+01D4AE ‹𝒮›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL S
 292 U+01D49F ‹𝒟›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL D
 285 U+01D4B3 ‹𝒳›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL X

TDD dictum'unu ele al: "Test edilmemiş kod bozuk kod", ve "unceccised kod bozuk kod" olarak tekrar yazın ve programcıların BMP olmayan kod noktaları ile ne sıklıkla uğraşmaları gerektiğini düşünün.

UTF-16 ile değişken genişlikteki bir kodlama olarak uğraşmamakla ilgili hataların UTF-8'deki eşdeğer hatalardan fark edilmemesi çok daha muhtemeldir . Bazı programlama dilleri UCS-2 yerine UTF-16 olarak vermeyi garanti etmemektedir ve bazı yüksek seviye programlama dilleri kod noktaları yerine kod birimlerine erişim sunar (C kodunun size erişim izni vermesi gerekir) wchar_tbazı platformların ne yapabileceğinden bağımsız olarak kullanırsanız kod noktaları .


16
"Değişken genişlikli bir kodlama olarak UTF-16 ile başa çıkmamaya bağlı hataların UTF-8'deki eşdeğer hatalardan fark edilmemesi çok daha muhtemeldir." Bu konunun özü ve dolayısıyla doğru cevabı.
Sean McMillan

3
Tam. UTF-8 kullanımınız boş ise, hemen anlaşılacaktır. UTF-8 kullanımınız boşsa, sadece nadir görülen Han karakterleri veya matematik simgelerini girdiğinizi fark edeceksiniz.
Mekanik salyangoz,

1
Çok doğru, fakat diğer taraftan, daha az sıklıkta böcek bulmak için şansa bağlı olmanız durumunda birim testleri nelerdir?
musiphil

@ musiphil: BMP olmayan karakterler için en son ne zaman ünite testi yaptınız?
ninjalj

1
Daha önceki ifademe değinmek için: UTF-8 ile bile, sadece bazı çalışma örneklerini gördükten sonra tüm davaları ele aldığınızdan emin olamazsınız. UTF-16 ile aynı: Kodunuzun hem vekiller hem de vekiller ile çalışıp çalışmadığını test etmeniz gerekir. (Birisi UTF-8'in en az dört ana vakayı varken, UTF-16'nın sadece iki tane olduğunu iddia edebilir.)
musiphil

40

UTF-16'yı düşünmenin zararlı olarak kabul edilebileceğini düşünüyorum, daha büyük bir unicode anlayışı kazanmanız gerektiğini söylüyor .

Sübjektif bir soru hakkında fikrimi sunduğum için oy kullanmadığım için, detaylı çalışayım. UTF-16 hakkında sizi rahatsız eden tam olarak nedir? UTF-8’de her şeyin kodlanmış olmasını tercih eder misiniz? UTF-7? Veya nasıl UCS-4? Tabii ki bazı uygulamalar, sürekli karakter kodunu işlemek için tasarlanmamıştır - ancak uluslararası sınırlar arasındaki iletişim için, özellikle günümüzün küresel bilgi alanında gereklidir.

Fakat gerçekten, eğer UTF-16'nın zararlı olarak algılanması gerektiğine inanıyorsanız, kafa karıştırıcı veya yanlış bir şekilde uygulanabilir (unicode kesinlikle olabilir), o zaman hangi karakter kodlaması yönteminin zararsız olduğu düşünülür?

EDIT: Açıklığa kavuşturmak için: Neden bir standardın uygun olmayan uygulamalarını standardın kalitesinin bir yansıması olarak düşünün? Başkalarının daha sonra belirttiği gibi, sadece bir uygulama uygun olmayan bir alet kullandığı için, aletin kendisinin kusurlu olduğu anlamına gelmez. Öyle olsaydı, muhtemelen "var anahtar kelimesi zararlı olarak kabul edildi" ya da "zararlı olarak kabul edilir" gibi şeyler söyleyebiliriz. Sanırım bu soru, standardın niteliğini ve niteliğini, birçok programcının onu doğru şekilde uygulama ve kullanmadaki zorluklarla karıştırdığını, bunun da unicode'un kendisinin nasıl çalıştığını anlama konusundaki yetersizliklerinden kaynaklandığını düşünüyorum.


33
-1: Artyom'un itirazlarından bazılarına değinmek yerine, sadece onu harekete geçirmeye ne dersiniz?

8
BTW: Bu makaleyi yazmaya başladığımda, neredeyse "Unicode'un Softeare makalesinde Joel'in zararlı sayılması gerekiyor mu" yazmasını istiyordum çünkü birçok hata var. Örneğin: utf-8 kodlaması 4 karaktere kadar ve 6 karakterden oluşmuyor. Ayrıca UCS-2 ve UTF-16'yı gerçekten farklı olan ayırt etmiyor - ve aslında bahsettiğim sorunlara neden oluyor.

32
Ayrıca, Joel'in bu makaleyi yazdığı zaman, UTF-8 standardının WAS 6 bayt olduğunu, 4 değil de yazdığını belirtmek gerekir. İnternet'teki çoğu şey gibi, birden fazla kaynaktan okumak ve kaynaklarınızın yaşının farkında olmak için ödeme yapar. Bağlantı "hepsinin sonu" olmalıydı, aksine bir başlangıç ​​noktasıydı.

7
Ben pic: utf-8 veya utf-32 olan: hemen hemen her durumda değişken uzunluk kodlaması (BMP dahil) veya her zaman sabit uzunluk kodlaması.

18
@iconiK: Aptal olma. UTF-16, kesinlikle metin işleme için fiili bir standart değildir . Bana her zaman (on yıldan uzun bir süredir) olan Perl'in dahili UTF-8 temsili içeren soyut karakterleri kullandığı metin işlemeye daha uygun bir programlama dili göster. Bu nedenle, her Perl programı otomatik olarak tüm Unicode'ları otomatik olarak kullanıcı aptal vekillerle etrafta dolaşmak zorunda kalmadan idare eder. Bir dizgenin uzunluğu, kod birimlerindeki değil kod noktalarındaki sayımıdır. Başka bir şey, geriye dönük uyumluluk içine geriye doğru koyarak aptallıktır.
tchrist

37

Utf-16 kodlamasında yanlış bir şey yok. Ancak, 16 bit birimleri karakter olarak gören diller muhtemelen kötü tasarlanmış sayılmalıdır. Her charzaman bir karakteri temsil etmeyen ' ' adlı bir türün olması kafa karıştırıcıdır. Çoğu geliştirici bir karakter tipinin bir kod noktasını veya karakteri göstermesini bekleyeceğinden, çoğu kod BMP'nin karakterlerine maruz kaldığında büyük olasılıkla kırılacaktır.

Ancak utf-32 kullanarak bile her 32 bit kod noktasının her zaman bir karakteri temsil edeceği anlamına gelmediğine dikkat edin. Karakterleri birleştirme nedeniyle gerçek bir karakter birkaç kod noktasından oluşabilir. Unicode asla önemsiz değildir.

BTW. Muhtemelen Utf-8 ile beslenen karakterlerin 8 bit olmasını bekleyen platform ve uygulamalara sahip aynı hata sınıfı vardır.


12
Java örneğinde zaman çizelgelerine bakarsanız ( java.com/en/javahistory/timeline.jsp ), öncelikle String'in geliştirilmesinin Unicode 16 bitken (1996'da değişti) olduğunu görüyorsunuz. BMP kodu olmayan noktaları, dolayısıyla karışıklığı ele alma becerisini geliştirmek zorunda kaldılar.
Kathy Van Stone

10
@Kathy: Yine de, C # için bir bahane değil. Genel olarak, bir CodePointtür kod olması , tek bir kod noktası (21 bit), bir CodeUnittür, tek bir kod birimi (UTF-16 için 16 bit) tutan bir Charactertür olması ve bir türün ideal olarak tam bir grafiğe sahip olması gerektiğine katılıyorum. Ama bu işlevsel olarak eşdeğerde String...
Joey

1
Bu cevap neredeyse iki yaşında, ama yardım edemem ama yorum yap. “Her zaman bir karakteri temsil etmeyen 'char' adında bir türe sahip olmak oldukça kafa karıştırıcı.” Yine de insanlar her zaman C ve benzerlerinde, tek bir baytta depolanabilen tamsayı verilerini temsil etmek için kullanırlar.
JAB

Ve karakter kodlamasını doğru işlemeyen bir sürü C kodu gördüm .
dan04

1
C # 'nin farklı bir bahanesi var: Windows için tasarlandı ve Windows UCS-2 üzerine kuruldu (bugün bile Windows API'lerinin UTF-8'i destekleyememesi çok can sıkıcı). Artı, Microsoft’un Java uyumluluğu istediğini düşünüyorum (.NET 1.0’ın Java uyumluluğu kitaplığı vardı, ancak Java desteğini çok hızlı bir şekilde bıraktılar - sanırım bu Sun’ın MS’e karşı açılmasından kaynaklanıyor?)
Qwertie

20

Kişisel tercihim her zaman UTF-8'i kullanmak. Neredeyse her şey için Linux'ta standart. Birçok eski uygulamayla geriye dönük olarak uyumludur. Latince olmayan karakterler için kullanılan diğer UTF formatları için kullanılan fazladan boşluk açısından çok az ek yük vardır ve latin karakterler için boşlukta önemli bir tasarruf vardır. İnternette latin dilleri yüce hüküm sürüyor ve sanırım öngörülebilecek gelecek için olacaklarını düşünüyorum. Orijinal gönderideki ana argümanlardan birine değinmek için: hemen hemen her programcı UTF-8'in bazen çok baytlık karakterleri olacağının farkındadır. Herkes bununla doğru bir şekilde ilgilenmiyor, ancak genellikle UTF-16 için söylenenden daha fazla olanın farkındalar. Ancak, elbette, başvurunuz için en uygun olanı seçmeniz gerekir. Bu yüzden ilk etapta birden fazla var.


3
UTF-16, BMP içindeki herhangi bir şey için daha basittir, bu yüzden bu kadar yaygın kullanılır. Ama ben de UTF-8 hayranıyım, aynı zamanda avantajına çalışan bayt sırası ile ilgili herhangi bir problemi yok.
Malcolm

2
Teorik olarak evet. Uygulamada, diyelim ki UTF-16BE gibi şeyler var, yani ürün reçetesiz büyük Endian dilinde UTF-16. Bu benim yaptığım bir şey değil, bu ID3v2.4 etiketlerinde izin verilen gerçek bir kodlama (ID3v2 etiketleri emiyor, ancak ne yazık ki yaygın olarak kullanılıyorlar). Ve bu gibi durumlarda, dıştan harfleri dıştan tanımlamanız gerekir, çünkü metnin kendisi BOM içermez. UTF-8 her zaman bir şekilde yazılır ve böyle bir problemi yoktur.
Malcolm

23
Hayır, UTF-16 daha basit değil. Daha zor. Yanıltıcı ve sabit genişlik olduğunu düşünerek sizi aldatıyor. Tüm bu kodlar kırıldı ve tüm Moreso'lar çünkü çok geç olmadan farketmediniz. NOKTADAKİ KAZANÇ: Dün Java çekirdeği kütüphanelerinde henüz aptal bir UTF-16 hatası buldum, bu sefer UCS-2 braindery altında bırakılan String.equalsIgnoreCase'de ve 16/17 geçerli Unicode kod puanlarında başarısız oldu. Bu kod ne zamandır etrafta? Buggy için mazeret yok. UTF-16 tamamen aptallığa ve bunun gerçekleşmesini bekleyen bir kazaya yol açar. UTF-16'dan çığlık atmayı çalıştırın.
tchrist

3
tchrist Bir UTF-16'nın sabit uzunluk olmadığını bilmemek için çok cahil bir geliştirici olmalı. Vikipedi ile başlarsanız, en üstte aşağıdakileri okuyacaksınız: "Kod noktası başına bir veya iki adet 16 bitlik kod birimi değişken uzunluklu bir sonuç üretir". Unicode SSS de aynı şeyi söylüyor: unicode.org/faq//utf_bom.html#utf16-1 . Bilmiyorum, UTF-16 değişken uzunluktaki her yere yazıldığında nasıl birisini aldatabilir? Yönteme gelince, asla UTF-16 için tasarlanmadı ve Unicode olarak kabul edilmemeliydi, bu kadar basit.
Malcolm

2
@tchrist İstatistikleriniz için bir kaynağınız var mı? İyi programcılar kıt olsa da, bence bu iyi, çünkü daha değerli hale geliyoruz. :) Java API'lerine gelince, karakter bazlı parçalar sonuçta kullanımdan kaldırılabilir, ancak bu kullanılmayacaklarının garantisi değildir. Uyumluluk nedeniyle kesinlikle kaldırılmayacaklar.
Malcolm

18

Eh, sabit boyutlu semboller kullanan bir kodlama var. UTF-32'yi kesinlikle kastediyorum. Ancak her sembol için 4 bayt çok fazla boşa harcanmıştır, neden günlük durumlarda kullanalım?

Aklıma gelen sorunların çoğu, bazı yazılımların Unicode standardının gerisine düştüğü, ancak durumu düzeltmek için hızlı olmadığı gerçeğinden kaynaklanmaktadır. Opera, Windows, Python, Qt - Hepsi UTF-16 yaygın olarak bilinmeden ve hatta ortaya çıkmadan önce ortaya çıktı. Bununla birlikte, Opera, Windows Gezgini ve Not Defteri'nde BMP dışındaki karakterlerde artık sorun olmadığını (en azından bilgisayarımda) doğrulayabiliyorum. Fakat yine de, programlar vekil çiftleri tanımıyorsa, UTF-16'yı kullanmazlar. Bu tür programlarla başa çıkmaktan kaynaklanan problemler ne olursa olsun, UTF-16'nın kendisi ile ilgisi yoktur.

Ancak, eski BMP destekli yazılım problemlerinin biraz abartıldığını düşünüyorum. BMP dışındaki karakterlere yalnızca çok özel durumlarda ve alanlarda rastlanır. Göre Unicode resmi SSS , "Hatta Doğu Asya metinde, vekil çiftleri insidansı ortalama olarak tüm metin depolama% 1'den de az olmalıdır". Tabii ki, BMP dışındaki karakterler ihmal edilmemelidir, çünkü bir program Unicode uyumlu değilse, ancak çoğu program bu karakterleri içeren metinlerle çalışmak için tasarlanmamıştır. Bu yüzden eğer desteklemiyorlarsa, tatsız, ama bir felaket değil.

Şimdi alternatifi düşünelim. UTF-16 olmasaydı, ASCII olmayan metinler için uygun bir kodlamaya sahip olmazdık ve UCS-2 için oluşturulan tüm yazılımların Unicode uyumlu kalması için tamamen yeniden tasarlanması gerekiyordu. İkincisi büyük olasılıkla Unicode'un benimsenmesini yavaşlatır. Ayrıca, UTC-8'in ASCII ile ilgili olarak yaptığı gibi UCS-2'deki metin ile uyumluluğunu koruyamazdık.

Şimdi, tüm eski sorunları bir kenara koyarsak, kodlamanın kendisine karşı çıkan argümanlar nelerdir? Bugünlerde geliştiricilerin UTF-16'nın değişken uzunluk olduğunu bilmediğinden şüpheliyim, her yerde Wikipedia'ya yazılan her yer var. Birisi karmaşıklığı muhtemel bir sorun olarak belirttiyse, UTF-16'nın ayrıştırılması UTF-8'den daha az zordur. Ayrıca, sadece UTF-16'da dize uzunluğunu belirlemekle uğraşmanın kolay olduğunu düşünmek yanlıştır. UTF-8 veya UTF-32 kullanıyorsanız, bir Unicode kod noktasının mutlaka bir karakter anlamına gelmediğinin farkında olmalısınız. Bunun dışında kodlamaya karşı önemli bir şey olduğunu sanmıyorum.

Bu nedenle kodlamanın kendisinin zararlı olarak kabul edilmesi gerektiğini düşünmüyorum. UTF-16 basitlik ve kompaktlık arasında bir uzlaşmadır ve ihtiyaç duyulan yerde gerekli olanı kullanmanın bir zararı yoktur . Bazı durumlarda ASCII ile uyumlu kalmanız gerekir ve UTF-8'e ihtiyacınız vardır, bazı durumlarda Han ideografları ile çalışmak ve UTF-16'yı kullanarak yer kazanmak istiyorsanız, bazı durumlarda sabit karakterleri gösteren genel karakterlerin gösterimini yapmanız gerekir. uzunluk kodlaması. Daha uygun olanı kullanın, doğru şekilde yapın.


21
Bu göz kırptı, Anglo merkezli bir bakış, Malcolm. Neredeyse "ASCII ABD için yeterince iyi - dünyanın geri kalanının bize uyması gerekiyor" ile aynı düzeyde.
Jonathan Leffler

28
Aslında ben Rusya'lıyım ve her zaman (kendi programlarım dahil) Kirilliklerle karşılaşıyorum, bu yüzden Anglo merkezli bir görüşüm olduğunu sanmıyorum. :) ASCII'den bahsetmek, unicode olmadığı ve belirli karakterleri desteklemediği için pek uygun değil. UTF-8, UTF-16, UTF-32 aynı uluslararası karakter setlerini destekler, sadece kendi alanlarında kullanılmak üzere tasarlanmıştır. Ve bu tam olarak benim açımdan: çoğunlukla İngilizce kullanıyorsanız, UTF-8'i kullanın, çoğunlukla kiril kullanıyorsanız, UTF-16'yı kullanın, eski dilleri kullanıyorsanız UTF-32'yi kullanın. Oldukça basit.
Malcolm

16
"Doğru değil, Japonca, Çince veya Arapça gibi Asya dilleri de BMP'ye aittir. BMP'nin kendisi de aslında bugünlerde kullanılan tüm betikleri içerecek kadar büyük ve kesinlikle büyüktür" Bu çok yanlış. BMP, 0xFFFF karakterleri içeriyor (65536). Sadece Çinliler bundan daha fazlasına sahiptir. Çin standartları (GB 18030) bundan daha fazlasına sahiptir. Unicode 5.1, zaten 100.000'den fazla karakter tahsis etti.

12
@Marcolm: "BMP'nin kendisi aslında çok büyük ve bugünlerde kullanılan tüm betikleri içerecek kadar kesinlikle büyük" Doğru değil. Bu noktada Unicode zaten yaklaşık 100.000 karakter tahsis etti, BMP'nin yerine daha fazlasını sağlayabiliyordu. BMP dışında Çince karakterlerin büyük parçaları var. Bazıları GB-18030 (zorunlu Çin standardı) tarafından talep edilmiştir. Diğerleri (zorunlu olmayan) Japon ve Kore standartlarına göre zorunludur. Dolayısıyla, bu pazarlarda bir şey satmaya çalışırsanız, BMP desteğinin ötesine ihtiyacınız var.

8
UTF-16 kullanan ancak yalnızca dar BMP karakterlerini işleyebilen herhangi bir şey aslında UTF-16'yı kullanmaz. Bu adamcağız ve bozuk. OP'nin öncülü sağlamdır: UTF-16 zararlıdır, çünkü naif insanları bozuk kod yazmaya zorlar. Unicode metinleri işleyebilirsiniz ya da yapamazsınız. Yapamazsanız, o zaman sadece ASCII metin işleme kadar aptal olan bir altküme seçiyorsunuzdur.
tchrist

16

Özellikle Doğu Asya dillerinde yıllar süren Windows uluslararasılaştırılması beni mahvedebilir, ancak dizelerin program içi dahili gösterimi için UTF-16'ya, düz metin benzeri belgelerin ağ veya dosya depolaması için UTF-8'e dayanıyorum. UTF-16 genellikle Windows'ta daha hızlı işlenebilir, bu yüzden Windows'ta UTF-16 kullanmanın temel yararı budur.

UTF-16'ya sıçraması, uluslararası metinleri işleyen ortalama ürünlerin yeterliliğini önemli ölçüde artırdı. Vekil çiftlerin göz önünde bulundurulması gereken (sadece silmeler, sokmalar ve çizgi kırma) ve ortalama durum çoğunlukla düz geçiş olduğunda, sadece birkaç dar durum söz konusudur. Ve JIS varyantları gibi daha önceki kodlamaların aksine, UTF-16 vekil çiftleri çok dar bir aralıkta sınırlar, böylece kontrol gerçekten hızlıdır ve ileri ve geri çalışır.

Verilmiş, kabaca doğru kodlanmış UTF-8'de de hızlı. Ancak, vekil çiftleri iki UTF-8 dizisi olarak yanlış kodlayan birçok kırık UTF-8 uygulaması da var. Yani UTF-8 de kurtuluş garantisi vermez.

IE, vekilleri 2000’den bu yana oldukça iyi bir şekilde bir araya getirir, tipik olarak UTF-8 sayfalarından dahili bir UTF-16 temsiline dönüştürülmesine rağmen; Firefox’un da haklı olduğuna eminim, bu yüzden Opera’nın ne yaptığını umursamıyorum.

UTF-32 (aka UCS4) çoğu uygulama için anlamsızdır, çünkü çok fazla alan gerektirir, bu yüzden hemen hemen bir nonsterter.


6
UTF-8 ve vekil çiftler hakkında yorumunuzu almadım. Vekil çiftler yalnızca UTF-16 kodlamasında anlamlı olan bir kavramdır, değil mi? Belki de doğrudan UTF-16 kodlamasından UTF-8 kodlamasına dönüştüren kod bunu yanlış yapabilir ve bu durumda sorun UTF-8'i değil, UTF-16'yı yanlış okuyor. Bu doğru mu?
Craig McQueen

11
Jason'ın bahsettiği şey, kasıtlı olarak UTF-8'i bu şekilde uygulayan bir yazılımdır: bir yedek çift oluşturun, ardından UTF-8 her bir yarısını ayrı ayrı kodlar. Bu kodlamanın doğru adı CESU-8'dir, ancak Oracle (örn.) UTF-8 olarak yanlış tanıtır. Java, nesne serileştirme için benzer bir şema kullanır, ancak açıkça "Modifiye UTF-8" olarak ve yalnızca dahili kullanım için belgelenmiştir. (Şimdi, eğer insanlar bu dokümanları OKUYOR ve DataInputStream # readUTF () ve DataOutputStream # writeUTF () 'yi uygun olmayan bir şekilde kullanmayı bırakabilirsek ...)

AFAIK, UTF-32 hala değişken uzunluklu kodlamadır ve belirli kod noktası aralığı olan UCS4'e eşit değildir.
Eonil

@Eonil, UTF-32, yalnızca bir UCS5 veya daha büyük bir şeye sahip olan bir Unicode standardına sahipsek UCS4'ten ayırt edilebilir.
JasonTrue,

@ JasonTrue Yine de, sadece sonuçlar tesadüfen eşittir, tasarım tarafından garanti edilmez. Aynı şey 32 bitlik bellek adresleme, Y2K, UTF16 / UCS2'de de oldu. Yoksa bu eşitlik konusunda herhangi bir garantimiz var mı? Eğer varsa, bunu memnuniyetle kullanırdım. Ama olası bir kırılabilir kod yazmak istemiyorum . Bir karakter seviyesi kodu yazıyorum ve UTF <-> kod noktası arasında geçiş yapmanın garantili bir yolunun olmaması beni çok rahatsız ediyor.
Eonil

16

UTF-8 kesinlikle, muhtemelen yüksek performanslı rastgele erişime ihtiyaç duyan algoritmalarda dahili kullanım için UTF-32 eşliğinde kullanılabilecek bir yoldur (ancak karakterleri birleştirmeyi yok sayar).

Hem UTF-16 hem de UTF-32 (ve LE / BE değişkenlerinin yanı sıra) endiyan sorunlarından muzdariptir, bu nedenle asla harici olarak kullanılmamalıdırlar.


9
Sabit zamanlı rastgele erişim UTF-8 ile de mümkündür, sadece kod noktaları yerine kod birimlerini kullanın. Belki de gerçek rasgele kod erişimine ihtiyacınız vardır, ancak bir kullanım durumu görmedim ve bunun yerine rasgele grafik küme erişimi isteyebilirsiniz.

15

UTF-16? kesinlikle zararlı. Burada sadece tuz tanem var, ancak bir programdaki metin için kabul edilebilir üç kodlama var:

  • ASCII: Daha iyi bir şey sağlayamayan düşük seviyeli şeyler (örneğin: mikrodenetleyiciler) ile çalışırken
  • UTF8: dosyalar gibi sabit genişlikte bir ortamda depolama
  • tamsayı kod noktaları ("CP"?): programlama diliniz ve platformunuz için en uygun tam sayı dizisidir (düşük dirençler sınırında ASCII'ye dönüşür). Eski bilgisayarlarda int32 ve 64 bit adreslemeli bir şeyde int64 olmalıdır.

  • Açıkçası, eski koda olan arayüzler, eski kodun doğru çalışmasını sağlamak için gereken kodlamayı kullanır.


4
@simon buchan, U+10ffffkod noktaları bittiğinde (eğer değilse) max, pencereden dışarı çıkar. Bununla birlikte, int32'nin p64 sisteminde hız için kullanılması muhtemelen güvenlidir, çünkü U+ffffffffkodunuzu 2050 civarında 128 bit sistemler için yeniden yazmak zorunda kalmadan önce aşacaklarından şüpheliyim . "mümkün olan en büyüklere" (muhtemelen int256 veya bignums veya başka bir şey olabilir) aksine) uygundur.
David X

1
@Did: Unicode 5.2 107,361 kod noktasını kodlar. Kullanılmayan 867,169 kod noktası var. "ne zaman" sadece saçma. Unicode kod noktası, UTF-16'nın dayandığı bir özellik olan 0 ile 0x10FFFF arasında bir sayı olarak tanımlanır . (Ayrıca, 2050, 64 bit bir sistem adres alanının tamamında İnternet'in tamamını tutabildiğinde, 128 bit sistemler için bir tahminin çok düşük olduğu görülüyor.)

3
@David: "Ne zaman", Unicode kod noktalarının tükenmesinden bahsediyordu, 128 bitlik bir anahtar değil, evet, gelecek birkaç yüzyıl içinde olacak. Hafızanın aksine, üstel karakter büyümesi yoktur, bu nedenle Unicode Konsorsiyumu, yukarıda asla bir kod noktası tahsis etmeyeceklerini özel olarak garanti etmiştir . Bu gerçekten 21 bitin herhangi biri için yeterli olduğu durumlardan biridir . U+10FFFF

10
@Simon Buchan: En azından ilk iletişime kadar. :)

3
Unicode, U + FFFF üzerinde de kod noktası olmayacağını garanti etmek için kullanılır.
Shannon Severance

13

Unicode , 0x10FFFF (1.114.112 kodlarına) kadar kod noktalarını tanımlar, çok dilli bir ortamda çalışan dizeler / dosya adları vb. İle ilgili tüm uygulamaların bu sorunu çözmesi gerekir.

Utf-16 : yalnızca 1.112.064 kodlarını kapsar. Unicode'un sonunda olanlar 15-16 uçaklarından olmasına rağmen (Özel Kullanım Alanı). Utf-16 kavramının kırılması dışında gelecekte daha fazla büyüyemez .

Utf-8 : teorik olarak 2,216,757,376 kodları kapsar. Unicode kodlarının mevcut aralığı, maksimum 4 byte dizisi ile temsil edilebilir. O ile zarar vermez bayt sırası bu ASCII ile "uyumlu" olduğu, sorunun.

Utf-32 : teorik olarak 2 ^ 32 = 4,294,967,296 kodları kapsar. Şu anda kodlanmış değişken uzunluklu değildir ve muhtemelen gelecekte olmayacak.

Bu gerçekler açıklayıcıdır. Utf-16'nın genel kullanımının savunuculuğunu anlamıyorum . Değişken uzunluklu kodludur (endeksle erişilemez), şu anda bile tüm Unicode aralığını kapsama problemi vardır , bayt sırası ele alınmalıdır, vb. diğer yerler. Çok platformlu kod yazarken Utf-8'i doğal olarak kullanmak ve dönüşümleri yalnızca son noktalarda platforma bağımlı bir şekilde (önceden önerildiği şekilde) yapmak daha iyi olsa da. Dizine göre doğrudan erişim gerekli olduğunda ve hafıza sorun olmadığında, Utf-32 kullanılmalıdır.

Asıl sorun, Windows Unicode = Utf-16 ile ilgili birçok programcının değişken uzunluk kodlu olduğunu bile bilmemesi veya görmezden gelmesidir .

Genellikle * nix platformunda olduğu gibi oldukça iyidir, Utf-8 kodlu geniş c dizeleri (wchar_t *) Utf-32 olarak yorumlanır .


7
Not: UTF-16, Unicode Konsorsiyumu'nun 10FFFF'in ÜST Unicode aralığı ve tanımlanmış UTF-8 maksimum 4 bayt uzunluğa sahip olduğu ve açıkça geçerli kod noktası aralığındaki 0xD800-0xDFFF aralığının dışında olduğu ve bu kodun oluşturulması için kullanıldığına karar verdiği için Tüm Unicode'u kapsıyor. taşıyıcı çiftler. Bu nedenle, geçerli bir Unicode metni, bu kodlamaların her biriyle gösterilebilir. Ayrıca geleceğe büyüme hakkında. Görünüşe göre 1 Milyon kod noktası gelecekte çok da yeterli olmayacak.

7
@Kerrek: Yanlış: UCS-2 geçerli bir Unicode kodlaması değil. Tanımı gereği tüm UTF- * kodlamaları, değişim için yasal olan herhangi bir Unicode kod noktasını temsil edebilir. UCS-2, bundan daha azını ve bir kaçını daha fazla temsil edebilir. Tekrar ediyorum: UCS-2 geçerli bir Unicode kodlaması değil, ASCII'den daha fazla morezo.
tchrist

1
" Utf-8'in genel kullanımının savunuculuğunu anlamıyorum . Kodlanmış değişken uzunluktadır (endeks ile erişilemez)"
Ian Boyd

9
@Ian Boyd, bir dizgenin bireysel karakterine rastgele erişim düzeninde erişme ihtiyacı inanılmaz derecede abartılıyor. Çok nadir görülen bir karakter matrisinin köşegenini hesaplamak istemek kadar yaygındır. Dizeler hemen hemen her zaman sırayla işlenir ve UTF-8 karakter N '1' e eriştiğinden, UTF-8 karakter N + 1 'e eriştiğinden, hiçbir sorun yoktur. Dizelere rasgele erişim sağlamak için fazlasıyla az ihtiyaç vardır. UTF-8 yerine UTF-32'ye gitmenin depolama alanına değeceğini mi düşünüyorsun, ama benim için tamamen sorun değil.
tchrist

2
tchrist, size "dizisel" olarak ters yineleme eklerseniz ve bir dizginin izleyen ucunun bilinen bir dizgeyle daha küçük bir karşılaştırmasını biraz uzatırsanız, dizgelerin hemen hemen her zaman sırayla işleneceğini size vereceğim. Yaygın olarak kullanılan iki senaryo, dizelerin sonundan boşlukları keser ve yolun sonunda dosya uzantısını denetler.
Andy Dent,

11

Bunu listeye ekle:

Sunulan senaryo basittir (burada sunacağımdan daha da basit!): 1. WinForms TextBox bir formda boş duruyor. 20'ye ayarlanmış bir MaxLength var .

2.Kullanıcı TextBox içine yazar veya belki de metni yapıştırır.

3. Metin Kutusuna ne yazdığınız veya yapıştırdığınızın hiçbir önemi yoktur, 20 ile sınırlandırılırsınız, ancak sempatik olarak 20'nin üzerindeki metinde bip sesi çıkarır (burada YMMV; bana bu etkiyi verecek şekilde ses düzenimi değiştirdim!).

4.Küçük metin paketi daha sonra heyecan verici bir maceraya başlamak için başka bir yere gönderilir.

Şimdi bu kolay bir senaryodur ve herkes bunu boş zamanlarında yazabilir. Kendimi WinForms kullanarak birden çok programlama dilinde yazdım çünkü sıkıldım ve daha önce hiç denemedim. Ve birden fazla gerçek dilde metin yazarken, çünkü bu yoldan kabloluyum ve çılgınca evrendeki herkesten daha fazla klavye düzenine sahibim.

Sıkıntıyı hafifletmek için Magic Carpet Ride adını bile verdim .

Bu işe yaramadı, buna değerdi.

Bunun yerine, şu 20 karakteri Magic Carpet Ride formuma girdim :

0123401234012340123 𠀀

Ahh.

Bu son karakter, Unicode'un ilk Uzatma B ideografı olan U + 20000'dir (yani, U + d840 U + dc00, yakın arkadaşlarına, olduğu gibi, deforme edilmekten utanmadığı)

görüntü tanımını buraya girin

Ve şimdi bir top oyunumuz var.

Çünkü TextBox.MaxLength hakkında konuştuğunda

Metin kutusuna manuel olarak girilebilecek maksimum karakter sayısını alır veya ayarlar.

gerçekte ne demek

Metin kutusuna manuel olarak girilebilecek maksimum UTF-16 LE kod birimi sayısını alır veya ayarlar ve dilbilgisi karakterine sahip, sadece birinin takıntılı olduğu bir dilbilimsel karakter anlayışıyla şirin oyunları oynamaya çalışan herhangi bir dizeden acımasızca keser Kaplan arkadaşının rahatsız edici bulacağını söyledi (daha fazla bilgi alması gerekiyor!).

Dokümanı güncellemeye çalışacağım ve göreceğim
... UCS-2 - UTF-16 serilerini hatırlayan normal okuyucular , TextBox.MaxLength'ın basit kavramına olan mutsuzluğumu ve en azından bu durumda nasıl ele almaları gerektiğini not edecek Draconian davranışının yasadışı bir sıra oluşturduğu durumlarda, .Net Framework’ün diğer bölümlerinin

  • System.Text.EncoderFallbackException: Dizin 0'daki Unicode karakter \ uD850, belirtilen kod sayfasına çevrilemedi. *

istisna, bu dizgiyi .NET Framework'ün herhangi bir yerine iletirseniz (meslektaşım Dan Thompson'ın yaptığı gibi).

Şimdi tamam, belki de tam UCS-2 - UTF-16 serisi pek çok kişinin ulaşamayacağı bir yerde.
Ancak TextBox.Text’in bir System.String üretmeyeceğini beklemek mantıklı değil mi? Bu başka bir .Net Framework parçasının atmasına neden olmaz mı? Demek istediğim, kontrolde bir olay şeklinde, size daha akıllı kesimi kolayca ekleyebileceğiniz bir kısaltmayı söyleyen bir şans olması gibi değil - kontrolün kendisinin yapmasının sakıncalı olmadığını doğrulamak. Beklenmedik istisnaların bir uygulamayı kaba bir hizmet reddi olarak feshetmesine yol açabilecek şekilde sınıflandırabilirseniz, bu serseri kontrolünün güvenlik sorunlarına yol açabilecek bir güvenlik sözleşmesini ihlal ettiğini söyleyeceğim kadar ileri giderim. Neden herhangi bir WinForms süreci ya da yöntemi ya da algoritması ya da tekniği geçersiz sonuçlar üretmeli?

Kaynak: Michael S. Kaplan MSDN Blog


Teşekkürler, çok iyi bağlantı! Onu sorudaki sorunlar listesine ekledim.

9

UTF-16'nın zararlı olduğunu söyleyemem. Zarif değil, ancak GB18030'un GB2312 ve UTF-8'in de ASCII ile yaptığı gibi UCS-2 ile geriye dönük uyumluluk amacına hizmet ediyor.

Ancak, Microsoft ve Sun'ın 16 bitlik karakterlerin etrafında büyük API'ler oluşturmasından sonra, Unicode'un yapısında köklü bir değişiklik yapmak zararlıydı. Değişimin farkındalığının yayılmaması daha zararlıydı.


8
UTF-8, ASCII'nin bir süpersetidir, ancak UTF-16, UCS-2'nin bir süpermarketi değildir. Neredeyse bir üst ayar olmasına rağmen, UCS-2'nin UTF-8'e doğru bir şekilde kodlanması, CESU-8 olarak bilinen istismarla sonuçlanır; UCS-2'nin vekilleri yoktur, sadece sıradan kod noktaları vardır, bu yüzden bunlar böyle tercüme edilmelidir. UTF-16'nın asıl avantajı, bir UCS-2 kod tabanını yükseltmenin UTF-8 için yeniden yazmanın tamamından daha kolay olmasıdır. Komik mi?

1
Elbette, teknik olarak UTF-16, UCS-2'nin bir süper ürünü değildir, ancak U + D800 ila U + DFFF ne zaman UTF-16 vekiller dışında bir şey için kullanılmıştı ?
dan04

2
Önemli değil. Biz bytestream'den kör bir şekilde geçmekten başka bir işlem, UCS-2 olarak kabul ediyorsanız yapamayacağınız vekil çiftlerin kodunu çözmenizi gerektirir.

6

UTF-16, işleme ve alan arasındaki en iyi uzlaşmadır ve bu nedenle çoğu büyük platform (Win32, Java, .NET) onu dizelerin dahili gösterimi için kullanır.


31
-1, çünkü UTF-8'in daha küçük olması veya önemli ölçüde farklı olmaması muhtemel. Bazı Asya dilleri için UTF-8, glif başına üç bayt iken, UTF-16 yalnızca iki iken, bu UTC-8'in ASCII için yalnızca bir bayt olmasıyla dengelenir (bu, ürün isimlerinde, komutlarda ve benzerlerinde asya dillerinde bile görülür). bir şeyler). Ayrıca, bahsedilen dillerde, bir glif latin karakterinden daha fazla bilgi taşır, bu nedenle daha fazla yer kaplaması için haklı çıkar.

32
Her iki seçeneğin de en kötü taraflarını birleştirmeyi iyi bir uzlaşma olarak adlandırmam.

18
UTF-8'den daha kolay değil. Değişken uzunlukta da.
luiscubal

36
UTF-16'nın yararları hakkında bir kenara bırakmak: Atıfta bulunduğunuz şey UTF-16'yı kullanmak için Windows, Java veya .NET'in nedeni değil . Windows ve Java, Unicode'un 16 bitlik bir kodlama olduğu zamana dayanıyor. UCS-2 o zaman mantıklı bir seçimdi. Unicode 21 bitlik bir kodlama haline geldiğinde UTF-16'ya geçiş mevcut platformların sahip olduğu en iyi seçimdi. Bunun kullanım kolaylığı veya uzlaşma tehlikesiyle hiçbir ilgisi yoktu. Bu sadece bir miras meselesi.
Joey

10
.NET, burada Windows mirasını devralır.
Joey,

6

UTF-16'nın amacını hiç anlamadım. En verimli alanı temsil etmek istiyorsanız UTF-8 kullanın. Metni sabit uzunlukta olarak ele almak istiyorsanız, UTF-32'yi kullanın. İkisini de istemiyorsanız, UTF-16'yı kullanın. Daha da kötüsü, UTF-16'daki tüm genel (temel çok dilli düzlem) karakterleri tek bir kod noktasına uyduğundan, UTF-16'nın sabit uzunlukta olduğunu varsayan hataların zor ve ince olacağını düşünür, ancak Bu UTF-8 ile, uluslararası hale getirmeye çalıştığınız anda kodunuz hızlı ve yüksek sesle başarısız olacaktır.


6

Henüz yorum yapamadığımdan, bunu bir cevap olarak yazıyorum, çünkü yazarlarla başka türlü bağlantı kuramıyorum utf8everywhere.org. Diğer yığın değişimlerinde yeterince üne sahip olduğum için yorum ayrıcalığını otomatik olarak alamıyorum.

Bu, Görüş'e yapılan bir yorum anlamına gelir : Evet, UTF-16'nın zararlı bir cevap olduğu düşünülmelidir .

Bir küçük düzeltme:

Yanlışlıkla bir UTF-8 geçişini birini engellemek için char*Windows API işlevlerinin ANSI-string sürümleri içine bir tanımlamalıdır UNICODEdeğil _UNICODE. _UNICODEgibi harita işlevleri _tcsleniçin wcslendeğil, MessageBoxiçin MessageBoxW. Bunun yerine, UNICODEtanım ikincisi ile ilgilenir. Kanıt olarak, bu MS Visual Studio 2005'in WinUser.hbaşlığından:

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

En azından bu hatanın düzeltilmesi gerekiyor utf8everywhere.org.

Öneri:

Belki de rehber, bir veri yapısının Geniş dize versiyonunun açıkça kullanılmasının bir örneğini içermeli, onu kaçırmayı / unutmayı daha kolay hale getirmek için. Geniş dizili veri yapılarının sürümlerinin kullanılması Geniş dizili işlev sürümlerinin kullanılması, birinin yanlışlıkla böyle bir işlevin bir ANSI dizesi sürümünü çağırması olasılığını azaltır.

Örnek olarak:

WIN32_FIND_DATAW data; // Note the W at the end.
HANDLE hSearch = FindFirstFileW(widen("*.txt").c_str(), &data);
if (hSearch != INVALID_HANDLE_VALUE)
{
    FindClose(hSearch);
    MessageBoxW(nullptr, data.cFileName, nullptr, MB_OK);
}

Kabul; Teşekkürler! Belgeyi güncelleyeceğiz. Belge hala daha fazla geliştirmeye ve veritabanları hakkında bilgi eklemeye ihtiyaç duyuyor. İfadelerin katkılarını almaktan mutluluk duyuyoruz.
Pavel Radzivilovsky

@PavelRadzivilovsky _UNICODEhala orada :(
cubuspl42

hatırlattığın için teşekkürler. cubus, Jelle, Bizim kullanıcı SVN için ister misiniz?
Pavel Radzivilovsky

@Pavel Tabii, memnun olurum!
Jelle Geerts

@JelleGeerts: Bu gecikme için özür dilerim. Bizimle her zaman e-postalarımız (manifestodan gelen bağlantı) veya Facebook ile iletişime geçebilirsiniz. Bulmamız kolay. Buraya getirdiğiniz sorunu düzelttiğimize inanıyorum (ve sizi oraya yatırdım), UTF-8'e karşı UTF-16 tartışmalarının tümü hala geçerli. Katkıda bulunmak için daha fazla bilginiz varsa, bu özel kanallar aracılığıyla bizimle iletişime geçmekten çekinmeyin.
ybungalobill

5

Birisi UCS4 ve UTF-32'nin aynı olduğunu söyledi. Hayır, ama ne demek istediğini biliyorum. Bunlardan biri olsa da, diğerinin kodlamasıdır. Keşke ilkden endian'ı belirtmeyi düşünmeseydiler, böylece burada endianess savaşı da yapmazdık. Bunun olacağını görmediler mi? En azından UTF-8 her yerde aynı (6-byte'lık orijinal spesifikasyona uymadığı sürece).

UTF-16 kullanıyorsanız , çok baytlı karakterleri işlemeyi dahil etmeniz gerekir . 2n'yi bir bayt dizisine dizine sokarak Nth karakterine gidemezsiniz. Yürümek ya da karakter indeksine sahip olmalısın. Aksi takdirde bir hata yazdın.

C ++ 'nın şu anki taslak özelliği, UTF-32 ve UTF-16'nın küçük endian, büyük endian ve belirtilmemiş varyantları olabileceğini söylüyor. Gerçekten mi? Unicode, herkesin en başından beri küçük endian yapmak zorunda olduğunu belirtmiş olsaydı, her şey daha basit olurdu. (Ben de büyük-endian ile iyi olurdu.) Bunun yerine, bazı insanlar bunu bir şekilde, bir başkasını uyguladı ve şimdi hiçbir şey için sersemlikten mahrum kaldık. Bazen yazılım mühendisi olmak utanç verici.


Belirtilmemiş endianitenin, dizenin hangi şekilde okunması gerektiğini belirlemek için kullanılan ilk karakter olarak BOM içermesi beklenir. UCS-4 ve UTF-32 aslında bugünlerde aynıdır, yani 32 bit bir tamsayıda saklanan 0 ile 0x10FFFF arasındaki sayısal bir UCS değeri.

5
@Tronic: Teknik olarak, bu doğru değil. UCS-4 herhangi bir 32-bit tam sayıyı saklayabilse de, UTF-32'nin 0xFFFF, 0xFFFE ve tüm vekiller gibi değiş tokuş için yasal olmayan karakter dışı kod noktalarını kaydetmesi yasaktır. UTF, dahili bir kod değil bir aktarım kodlamasıdır.
tchrist

Çeşitlilik sorunları, farklı işlemciler farklı bayt siparişleri kullanmaya devam ettiği sürece kaçınılmazdır. Bununla birlikte, UTF-16'nın dosya depolanması için "tercih edilen" bir bayt sırası olup olmaması hoş olabilirdi.
Qwertie

UTF-32 kod noktaları için sabit genişlikte olsa da , karakterler için sabit genişlikte değildir . ("Birleştirme karakterleri" olarak adlandırılan bir şey duydunuz mu?) Yani N''inci karaktere , 4N'yi bayt dizisine dizine sokarak gidemezsiniz .
musiphil

2

Geliştiricinin yeterince dikkatli olmasının zararlı olduğunu düşünmüyorum.
Ve eğer iyi biliyorlarsa bu işlemi kabul etmeleri gerekir.

Bir Japon yazılım geliştiricisi olarak, UCS-2'yi yeterince büyük buluyorum ve alanı sınırlandırıyorum, mantığı basitleştiriyor ve çalışma zamanı belleğini azaltıyor, bu nedenle utc-16'yı UCS-2 sınırlaması altında kullanmak yeterince iyi.

Kod noktaları ve baytların orantılı olduğunu varsayan dosya sistemi veya başka bir uygulama vardır, böylece ham kod noktası sayısının bazı sabit boyutta depolamaya uygun olacağı garanti edilebilir.

Bunun bir örneği, UCS-2'yi dosya adı depolama kodlaması olarak belirten NTFS ve VFAT'dir .

Bu örnek gerçekten UCS-4'ü desteklemeyi istiyorsa, yine de her şey için utf-8'i kullanmayı kabul edebilirim, ancak sabit uzunluk aşağıdaki gibi iyi noktalara sahiptir:

  1. Uzunluğa göre boyutu garanti edebilir (veri boyutu ve kod noktası uzunluğu orantılıdır)
  2. hash araması için kodlama numarasını kullanabilir
  3. sıkıştırılmamış veriler makul boyuttadır (utf-32 / UCS-4 ile karşılaştırıldığında).

Herhangi bir gömülü aygıtta bile bellek / işlem gücünün ucuz olması durumunda, ekstra önbellek hataları veya sayfa hataları ve ekstra bellek kullanımı için cihazın biraz yavaş olduğunu kabul edebiliriz, ancak bu yakın gelecekte gerçekleşmeyecek sanırım ...


3
Bu yorumu okuyanlar için, UCS-2'nin UTF-16 ile aynı şey olmadığını belirtmeye değer. Lütfen anlamak için farklılıkları araştırın.
mikebabcock

1

"En popüler kodlamalardan biri olan UTF-16'nın zararlı olduğu düşünülmeli mi?"

Oldukça muhtemel, ancak alternatiflerin mutlaka daha iyi olduğu düşünülmemelidir.

Temel sorun, glifler, karakterler, kod noktaları ve bayt dizileri hakkında birçok farklı kavramın olmasıdır. Bunların her biri arasındaki haritalama, normalleştirme kütüphanesinin yardımı ile bile önemsiz değildir. (Örneğin, Latin dilindeki bir komut dosyasıyla yazılan Avrupa dillerindeki bazı karakterler tek bir Unicode kod noktasıyla yazılmaz. Ve bu karmaşıklığın daha basit bir ucunda!) Bunun anlamı her şeyin doğru olması oldukça şaşırtıcı. zor; tuhaf hatalar beklenir (ve sadece burada onlar hakkında sızlanmak yerine, ilgili yazılımın sağlayıcılarına söyleyin ).

UTF-16'nın zararlı olarak kabul edilmesinin tek yolu, örneğin, UTF-8'in BMP dışındaki kod noktalarını kodlamanın farklı bir yoluna sahip olmasıdır (bir vekil olarak). Kod, kod noktasına göre erişmek veya yinelemek istiyorsa, bunun farktan haberdar olması gerektiği anlamına gelir. OTOH, "karakterleri" kabul eden önemli bir varolan kodun, her zaman iki baytlık bir miktara sığabileceği anlamına gelir - oldukça yaygın, eğer yanlışsa, varsayım - en azından hepsini yeniden inşa etmeden çalışmaya devam edebilir. Başka bir deyişle, en azından doğru şekilde kullanılmayan karakterleri görüyorsunuz !

Sorunuzu kafasına çevirip, Unicode'un lanet olası bütününün, zararlı olduğu düşünülmeli ve herkesin 8-bit kodlama kullanması gerektiğini (son 20 yılda, bunun neden olduğu yerde görmedim: korkunç) Çeşitli ISO 8859 kodlamaları, artı Kiril ve EBCDIC paketi için kullanılan tüm setler üzerinde kafa karışıklığı ve… iyi, Unicode tüm hataları için atıyor. Keşke farklı ülkelerin yanlış anlamaları arasında bu kadar kötü bir uzlaşma olmasaydı.


Şansımızı bilerek, birkaç yıl içinde kendimizi UTF-16’da boş alan bulduk. Meh.
Donal Fellows

3
Temel sorun, metnin aldatıcı bir şekilde zor olmasıdır. Bu bilgiyi dijital olarak temsil etmeye yönelik hiçbir yaklaşım karmaşık değildir. Tarihlerin zor olmasının, takvimlerin zor, zamanın zor, kişisel isimlerin zor, posta adreslerinin zor olmasının nedeni aynıdır: ne zaman dijital makineler insan kültürel yapılarıyla kesiştiğinde karmaşıklığı patlar. Bu hayatın bir gerçeği. İnsanlar dijital mantık üzerinde çalışmıyor.
Aristo Kapısı Pagaltzis
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.