Unicode Normalleştirici

Unicode'un dört normalleştirme biçimi vardır ve bunlar birbirinin yerine geçmez. NFC ve NFD aynı karakteri tek bir kod noktası ile bir temel artı birleştirici işaret arasında yeniden düzenler; NFKC ve NFKD bir adım daha ileri gider ve yalnızca birbirine benzeyen karakterleri yeniden yazar — fi ligatürü, tam genişlikli A, daire içindeki ①, Roma rakamı Ⅻ. Bu sayfa aynı metni dördünden de geçirir, her karakter için neyin neden değiştiğini söyleyen bir satır yazdırır, grafemleri kod noktaları ve UTF-8 baytlarıyla karşılaştırır ve iki dizgiyi seçtiğiniz biçim altında karşılaştırır. İkinci yarı, hiç görünmeyen karakterlerle ilgilidir: sıfır genişlikli boşluklar, birleştiriciler, çift yönlü denetimler, değişken seçiciler, C0 ve C1 denetim karakterleri, özel kullanım kod noktaları ve kırık vekil yarıları; her birinin konumu ve adıyla, ve metnin bir kopyasından onları ayıklama seçeneğiyle.
Tüm işlemler tarayıcınızda yerel olarak yapılır — verileriniz hiçbir sunucuya yüklenmez.

Normalleştirmenin ne olduğundan emin değil misiniz? Unicode normalleştirmesi sade bir dille açıklanmıştır — neden é tek bir karakter ya da iki karakter olabilir ve bunun neden bir girişi bozduğu.
Bildirilecek ve karşılaştırılacak biçim:
İki kutuyu şundan sonra karşılaştır:
NFC (henüz hiçbir şey yok)
NFD (henüz hiçbir şey yok)
NFKC (henüz hiçbir şey yok)
NFKD (henüz hiçbir şey yok)
Henüz karşılaştırılan bir şey yok. İki dizgiyi yapıştırın ve İki dizgiyi karşılaştır'a basın.
birinci dizgi, normalleştirilmiş (henüz hiçbir şey yok)
ikinci dizgi, normalleştirilmiş (henüz hiçbir şey yok)
Henüz taranan bir şey yok. Görünmez ve tehlikeli karakterleri tara'ya basın, ardından bu karakterlerin kaldırıldığı metni istiyorsanız Ayıkla'ya basın.
seçili sınıflar kaldırılmış metin (henüz hiçbir şey yok)
İlk kutuda Ctrl+Enter etkin kipi çalıştırır.
Bir kip seçin ve eylem düğmesine tıklayın. Normalleştir metninizin dört biçimini ve karakter başına bir satırı yazar; Karşılaştır iki dizginin normalleştirmeden sonra aynı olup olmadığını söyler; Tara görünmeyen karakterleri listeler ve onları ayıklayabilir. Öz-test düğmesi, bu sayfanın veri dosyasındaki her belgelenmiş durumu, görünmez ve kontrol tablolarının adını verdiği her karakteri yeniden çalıştırır ve sayıyı burada raporlar.
Her karakter, satır başına bir tane:karakterin ne olduğu, dört biçimin ona ne yaptığı ve nedeni. Gölgeli bir satır, en az bir biçimin değiştirdiği bir karakterdir; NFD sütunu, ayrışıyorsa karakterin neye ayrıştığını gösterir.
Bu kaç karakter eder?Aynı metin dört biçimde sayılır: grafem kümeleri (bir okurun saydığı), kod noktaları (Unicode'un atadığı), UTF-16 birimleri (JavaScript'in indekslediği) ve UTF-8 baytları (taşınan). Normalleştirme, birinci sütunu değiştirmeden sayıları ikinci ile üçüncü sütun arasında kaydırır.
Bulunanlar, göründüğü sırayla:konum kod noktalarını sayar, sınıf karakterin ait olduğu sınıftır ve not, o karakterin metni sonra okuyan her şey üzerinde ne yaptığını söyler.
Bu sayfanın şüpheli saydığı sınıflar:tablo doğrudan tarayıcının kendisinden yazdırılır, böylece bu sayfadaki sözcükler ve düğmelerin davranışı birbirinden ayrılamaz. Önem derecesi, bir karakterin masum olma olasılığı ile değil, bir karşılaştırma üzerindeki etkisiyle ilgilidir.
Özel kullanım karakterleri başka bir nedenle şüpheli olarak listelenir: çizilirler, ama üzerinde anlaşılmış bir anlamları yoktur; bu yüzden aynı kod noktası onu tanımlayan her yazı tipinde farklı bir resimdir.
Bu sayfanın kabul ettiği girdi boyutu ve nedeni:normalleştirme dizginin tamamının yeniden oluşturulmasıdır ve bu sayfa bunlardan birkaçını, bir tarama ve bir grafem sayımını birlikte yapar; bu yüzden maliyet girdinin uzunluğuyla düz bir çizgide artar. Aşağıdaki sınırlar, karakter başına tablonun belgede çizilmesi nedeniyle vardır; milyon satırlık bir tablo ise tarayıcıyı gerçekten durduran şeydir.
Unicode normalleştirmesi nedir?

Unicode bazı karakterleri birden fazla yolla yazmaya izin verir. é harfi tek bir kod noktası, U+00E9 olabilir ya da sıradan bir e ardından bir birleştirici akut aksan, U+0065 U+0301. İkisi ekranda aynı görünür, aynı basılır ve dizgi olarak farklıdırlar: farklı uzunlukları, farklı UTF-8 baytları vardır ve 'é' === 'é' false'tur.

Bu bir merak konusu değil, bir hata sınıfıdır. Birini mi yoksa diğerini mi aldığınız klavye düzenine, işletim sistemine, giriş yöntemine ve metnin bir kelime işlemciden kopyalanıp kopyalanmadığına bağlıdır. Bayt bayt karşılaştıran bir parola denetimi, bir veritabanı benzersiz dizini, bir engelleme listesi ya da bir önbellek anahtarı iki yazımı iki farklı değer olarak ele alır — böylece bir kullanıcı parolayı bir cihazda belirleyip diğerinden giriş yapamayabilir ve aynı sözcük "zaten alınmış" adlar listesinde iki kez görünebilir.

30 saniyelik özet: NFC ve NFD aynı metnin iki biçimde yazılmasıdır — NFC birleştirir (e + aksan tek bir karakter olur), NFD ayrıştırır (tek bir karakter e + aksan olur). Kayıpsız olmaları amaçlanır ve karşılaştırma ile depolama için kullanılacak iki biçimdir. NFKC ve NFKD, ilk ikisinin yaptığı her şeyi yapar ve ardından uyumluluk karakterlerini de değiştirir: fi ligatürü iki harfe, ½ 1⁄2'ye, ⅲ Roma rakamı XII'ye, tam genişlikli A sıradan bir A'ya dönüşür. Bu, tam olarak bir arama dizini ya da anahtar kelime filtresinin istediği şeydir ve parolaya asla uygulanmaması gereken şeydir.
Neden tek biçim değil de dört biçim

Bu bölünme, iki farklı amacın hizmet etmesinden gelir. Metni birleştirmek ve ayrıştırmak kanonik bir değişikliktir: sonuç aynı anlama gelir ve ilk iki biçim için hiçbir şey kaybolmaz. Ligatürleri, üst simgeleri, daire içine alınmış harfleri ve tam genişlikli biçimleri katlayarak yok etmek ise bir uyumluluk değişikliğidir: eşleştirme kolaylığı için yapılır ve Unicode'un farklı dediği iki dizgi arasındaki ayrımı gerçekten yok eder. Dört biçim, iki kararın her kombinasyonudur.

Yukarıdaki tablo, bu sayfanın veri dosyasındaki durum listesidir; platformun kendi String.prototype.normalize'ına karşı denetlenmiştir ve öz-test her satırını gözünüzün önünde yeniden denetler. İlk iki satırı birlikte okuyun: aynı metin, iki biçimde yazılmıştır ve normalleştirmeden sonra aynı dizgilerdir.

İşlenmiş örnekler

Bunlar Örnek düğmesinin adım adım geçtiği dizgilerdir; yanıt olarak yazılmış değil, sayfa tarafından canlı olarak normalleştirilmiştir. Her biri, bir biçimin ona görünür bir etkisi olduğu için seçilmiştir.

Uyumluluk karakterleri: NFKC neye mal olur

NFKC ve NFKD kayıplıdır ve kayıp kasıtlıdır. "Bu aynı sözcük mü" sorusunu yanıtlarlar, "bu aynı dizgi mi" sorusunu değil. Üç sonuç çıkar ve üçü de üretim kodunda yanlış yapılması kolay olanlardır:

  • Bir parolayı, bir belirteci ya da bir imzayı asla uyumluluk biçiminde saklamayın. İki farklı girdi aynı depolanan değere çöker ve bu, bir uzunluk ya da karakter denetimini daha zayıf bir hale getirir. Parolaları NFC ile normalleştirin (ya da hiç normalleştirmeyin) ve her iki tarafta da tam olarak aynı şeyi yaptıktan sonra bayt olarak karşılaştırın.
  • Uyumluluk katlaması tek bir karakteri birden fazlaya çevirebilir. fi ligatürü iki harfe dönüşen tek bir kod noktasıdır, bu yüzden normalleştirmeden önce uzunluğu doğrulanmış bir alan sonradan daha uzun olabilir. Önce normalleştirin, sonra doğrulayın, sonra depolayın.
  • NFKC her görünmez şeyi kaldırmaz. Bir değişken seçici NFKC ve NFKD'den sağ çıkar; sıfır genişlikli birleştirici de öyle. Bu yüzden bu sayfada bir tarama kipi vardır: normalleştirme bir karakterin şekli ve kimliği hakkında bir soruyu yanıtlar, tarayıcı ise bir şeyin orada olup olmadığı hakkında bir soruyu yanıtlar.
Grafemler, kod noktaları ve baytlar

Normalleştirme bu sayılardan ikincisini değiştirir ve genellikle birincisini olduğu gibi bırakır. Üç sayının hepsi "metnin uzunluğu" sayılır ve hepsi farklıdır; bu yüzden 20 karakter sınırı olan bir form alanı, 20 kod noktası, 30 UTF-16 birimi ve 47 bayt uzunluğundaki bir dizgiye ait olabilir.

Grafem sütunundaki sayı bir insanın saydığı şeydir. Onunla kod noktası sayısı arasındaki fark, tam olarak tarayıcının konusudur: 12 kod noktasından oluşan bir ad, 12 harf, aralarında 9 görünmez işaretle 3 harf ya da tek bir emoji olarak görüntülenebilir.

Göremediğiniz karakterler

Sıfır genişlikli boşluk hiç genişlik kaplamaz, hiçbir glifi değiştirmez ve gerçek bir kod noktasına sahip gerçek bir karakterdir. Ekranda aynı görünen iki tanımlayıcı, bunlardan biriyle farklılaşabilir; listedeki bir ad, yanındaki addan farklı sıralanan, aranan ve kimlik doğrulaması yapılan bir sahte olabilir. Çift yönlü denetimler için de durum aynıdır: bir dizgiyi yazıldığı sıradan farklı bir sırada gösterebilirler — dosya adlarını gizlemek için kullanılmış bir numara.

Üçüncü kipteki tarayıcı bunların her birini konumuyla birlikte listeler: sıfır genişlikli ve birleştirici karakterler, çift yönlü denetimler, değişken seçiciler, olağandışı boşluklar, C0 ve C1 denetim karakterleri, özel kullanım kod noktaları ve geçerli bir çiftin yarısı olmayan bir vekil — bu hiç karakter değildir. Sayfanın yukarısındaki sınıf tablosu her sınıfın ne yaptığını söyler ve ayıklama düğmesi, girdinize dokunmadan bu karakterlerin bir kopyasını kaldırır.

Bu sayfanın yakalamak için kurulduğu hatalar
  • İki dizgiyi normalleştirmeden karşılaştırmak. 'é' === 'é' yanlıştır. Karşılaştırmadan önce ikisini aynı biçimle normalleştirin ve karşılaştırdığınız dizinde de aynı biçimi kullanın.
  • Yalnızca bir tarafta normalleştirmek. Sorguyu normalleştirip saklanan değeri normalleştirmeyen bir arama hiçbir şey bulmaz ve bunu bir normalleştirme sorunundan çok bir veri sorunu gibi gösterir.
  • Bir uyumluluk biçimiyle bir biçimi NFC-güvenli sanmak. Bir parolaya uygulanan NFKC, olası parolaların alanını daraltır ve farklı olması amaçlanan girdileri birleştirir.
  • Bir normalleştirme biçiminin bir sahteciliği düzelteceğini varsaymak. Sıfır genişlikli birleştiriciyi, değişken seçiciyi ya da homoglifi kaldırmaz — Kiril а ile Latin a NFC'nin dokunmadığı farklı kod noktalarıdır.
  • Karakter sayısına güvenmek. Kullanıcının gördüğü sayı, bir veritabanı sütununun uyguladığı sayı ve bir bayt sınırının uyguladığı sayı üç farklı sayıdır ve yukarıdaki satırlar bunların ne kadar uzak olabileceğini gösterir.
  • NFC çıkacağını varsaymak. Bir giriş yönteminden, bir dosyadan ya da başka bir sistemden gelen metin, o sistemin ürettiği biçimdedir. Bu sayfa NFC ile başlar, çünkü web'in kullanmasının beklendiği biçim budur — girişinizin bu olduğu için değil.
Hızlı yanıtlar

“Aynı görünen iki dizgi neden eşit değil?”

Çünkü biri birleştirilmiş bir karakterle, diğeri ise bir temel harf artı birleştirici işaretle yazılmıştır ya da biri hiç bir şey çizmeyen bir karakter içerir. Karşılaştırma kipine geçin ve her kutuya bir dizgi koyun: sayfa normalleştirilmiş dizgilerin farklılaştığı ilk konumu ve her birinde o konumda ne olduğunu bildirir.

“Bir uygulamada hangi biçimi kullanmalıyım?”

İnsanın okuyacağı, görüntüleyeceği, depolayacağı ve arayacağı her şey için NFC — W3C'nin web için önerdiği biçim budur. NFD, arkanızdaki kodun temel harfler ve ayrı işaretler istediği durumda doğru yanıttır; metin işlemede ve macOS'taki bazı dosya sistemlerinde yaygındır. NFKC ya da NFKD'yi yalnızca depolamaktan çok eşleştirme yaptığınız yerde kullanın: arama dizinleri, anahtar kelime filtreleri, yinelenen tespiti.

“Zaten normalleştirilmiş bir dizgi, ona ekleme yaptıktan sonra hâlâ normalleştirilmiş mi?”

Mutlaka değil. Normalleştirme birleştirmeyle korunmaz: iki NFC dizgisini birleştirmek, NFC'nin farklı yazacağı bir dizi üretebilir, çünkü ikinci dizginin başındaki bir birleştirici işaret, birinci dizginin sonundaki karaktere eklenebilir. Yalnızca önce değil, birleştirmeden sonra da normalleştirin.

“Normalleştirme görünmez karakterleri kaldırır mı?”

Hayır, bir kısmi istisna dışında: NFKC ve NFKD kesilmeyen boşluğu sıradan bir boşlukla değiştirir; bu, bir uyumluluk katlamasının görünür bir sonucudur. Diğer her şey — sıfır genişlikli boşluklar, birleştiriciler, çift yönlü denetimler, değişken seçiciler — dört biçimden de değişmeden geçer. Üçüncü kip tam olarak bunun için vardır.

“Karakter sayısı değişmezken bayt sayısı neden değişiyor?”

Çünkü iki biçim, UTF-8'de farklı sayıda bayta mal olan farklı kod noktalarından oluşur. Önceden birleştirilmiş bir é iki bayttır; ayrıştırılmış çift ise üç bayttır. Yukarıdaki sayılar tablosu girdi ve her biçim için dört sayıyı yan yana yazdırır, böylece fark anlatılmak yerine görünür olur.

“Bu sayfadaki sonuçların doğru olduğunu nereden bileceğim?”

Öz-test'e basın. Bu sayfanın veri dosyasındaki her durumu normalleştirir, dört biçimi belgelenmiş ilişkiler için birbirine karşı yeniden denetler (NFC idempotenttir, bir NFC dizgisinin NFD'si orijinalin NFD'siyle aynıdır, vb.), görünmez ve kontrol tablolarında adı geçen her karakteri tarayıcıdan geçirir ve grafem durumlarını Intl.Segmenter ile karşılaştırır.

Standartlar ve atıf

Dört biçim ve tanımları Unicode Standardı, Ek 15'ten (Unicode Normalleştirme Biçimleri) alınmıştır. Ayrıştırma örneği olarak kullanılan kod noktaları standardın atadığı noktalardır; bu sayfa ayrıştırma tablolarını kendisi uygulamaz — tarayıcının kendi String.prototype.normalize fonksiyonunu çağırır, bu da platformun metin girişi, sıralama ve karşılaştırma için kullandığı aynı uygulamadır; dolayısıyla burada bildirilen şey, sistemin geri kalanının aynı dizgiyle ne yaptığıdır. Grafem kümeleri, tarayıcının sahip olduğu yerde Intl.Segmenter'dan, olmadığı yerde ise belgelenmiş bir yaklaşımdan gelir.

Sayfa metni bu site için yazılmıştır. Bu sayfadaki her çalışılmış örnek, sayfanın kendi kodu tarafından üretilmiş ve sonra veri dosyasının kayıtlı durum listesine karşı denetlenmiştir; bu liste de aynı karakterler için Unicode NormalizationTest verisine karşı denetlenmiştir. Görünmez ve tehlikeli karakter tabloları, insanlar tarafından okunabilir uyarılar için yazılmış, seçilmiş bir alt kümedir, tam Unicode güvenlik profili (UTS #39) değildir; sayfa bunu, sahip olmadığı bir tamlığı ima etmek yerine açıkça söyler.