2014-07-13 20 views
7

Dosya ve dizinleri içeren bir taşınabilir kitaplık yazıyorum. Girişim (dizin yolları) ve çıktı (dosya yolları) için UTF-8 kullanmak istiyorum. Sorun şu ki, Windows bana UTF-16-kullanılan-UCS-2 ve kod sayfaları arasında bir seçim sunuyor. Bu yüzden tüm UTF-8 dizelerini UTF-16'ya dönüştürmem, WinAPI'ye geçirmem ve sonuçları UTF-8'e çevirmem gerekiyor. C++ 11 sadece bunun için <locale> kitaplığı sağladı, anladığım kadarıyla, önceden tanımlanmış uzmanlıklardan hiçbiri UTF-8'i dahili (yani, benim-yanım) kodlama olarak kullanmıyor - en yakın olan UTF-16-to- olan UTF-8, istediğimin tam tersi. İşte ilk soru:C++ 11 yerel dizeleri UTF-8 dizelerinin iç gösterimi olarak kullanmak için nasıl kullanılır?

1) WinAPI çağrıları için UTF-8 dizelerimi UTF-16'ya dönüştürmek için codecvt thingamajigs nasıl kullanılır ve UTF-16 sonuçları UTF-8'e geri döndü?

Başka bir sorun: Linux'u da hedefliyorum. Linux'ta birçok farklı yer için çok iyi bir destek var - ve ben farklı olmak istemiyorum. Umarım herkes Linux makinelerinde UTF-8 kullanacaktır, ancak bunun kesin garantisi yoktur. Bu yüzden, Windows'a özgü yukarıdaki davranışı genişletmek ve her zaman UTF-8-to-system-locale-kodlamasını yapmak iyi bir fikir olacağını düşündüm. Görmüyorum hariç, mevcut sistem kodlamasını almak için C++ 11'in <locale> kitaplığında herhangi bir yol var! Varsayılan std :: locale yapıcısı, tek tek yerel ayarı yapar ve bunu yapmazsam, klasik "C" yerel değerini döndürür. Ve farkında olduğum başka bir alıcı yok. Yani ikinci soru:

2) Geçerli sistem yerel ayarı nasıl algılanır? <locale>'da bir şey var mı? Belki bazı standart C kütüphane işlevi veya (bu durumda daha az taşınabilir ancak tamam) POSIX API'sinde bir şey var mı?

+0

Bu soruyu geri almamdan önce düzenleyen kişiye: ikinci paragraf ** NOT ** ilk sorunun bir parçasıdır !!! – Xirdus

+2

olası bir kopyası [String, u16string & u32string arasında dönüştürme] (http://stackoverflow.com/questions/7232710/convert-between-string-u16string-u32string) – tclamb

+0

@tclamb Tam olarak bir kopya değil, ancak bu soruya cevaplar bana yardımcı ol. Bağlantı için teşekkürler. Ama soru 2) hala duruyor. – Xirdus

cevap

-1

Bu kitaplıkların standart kitaplıktaki tasarımı, çok baytlı karakter kodlamalarının (UTF-8 gibi) yalnızca harici depolama için (yani, diskteki dosyalardaki bayt dizileri) kullanıldığını ve bellekteki tüm karakterlerin boyut bakımından eşit olduğunu varsayar. Bu, std::basic_string<T>::operator[] gibi standartların dayattığı performans kısıtlamalarıyla tutarlı bir şekilde davranabileceği şeylerdir. Bu nedenle, UTF-8 veya başka bir MBCS'de (Japonca olanlar gibi) kodlanmış dosyaları kullanabilmenize rağmen, dizelerinizdeki bellekler char, char16_t, char32_t veya wchar_t olmalıdır.

Bu nedenle, standart kitaplıkta yapmak istediğiniz şey için bir eşleşme bulamıyorsunuz çünkü bellekte dizeler UTF-8'de saklanmayı amaçlamıyor. Bu, diskteki verilerin bayt akışı olarak yorumlandığı ve bunları bir dizgeye çevirmek için, byte akışının beklenen karakter kodlamasını belirtmeniz gereken diğer Java dillerine benzer. Bazı işletim sistemleri UTF-8 dizesini argv[] içine alabilir, ancak bu standart değildir. Windows'daki WinMain için Unicode etkinleştirilmiş giriş noktası, wchar_t için bir NUL sonlandırılmış işaretçi sağlar ve bir UTF-8 kodlanmış dizeye işaret eden bir char* değildir.

IBM'in International Components for Unicode kitaplığı, C++ standart kitaplığı ile tamamlayıcı ve birlikte çalışmak üzere tasarlanmış bir dizi bileşen sağlar. Kod dönüştürme imkanlarına bakarım. Standart, kod dönüştürme için <locale>'daki olanakları tanımlarken, UTF-8'den char16_t, char32_t veya wchar_t'a eşlemek için bir kod dönüştürme özelliğinin varlığını garanti etmez. Böyle bir şey varsa, yalnızca uygulamanızın ayrıntılarına göre elde edersiniz. ICU kütüphanesi, bu işlevselliği herhangi bir C++ uygulaması için portably sağlar. UTF-8 dizelerini char dizgisine göre daha geniş bir biçimde çözen hataların iyi bir şekilde desteklendiği ve iyi kullanıldığı ve iyi bir şekilde kullanılmadığı bilinmektedir.

Konrad, bir yorumda UTF-8 Her Yer Manifestosundan bahsetti.Bu ilginç bir okuma oldu ve size yukarıda belirtmiş olduğunuz sorunlara çözüm bulmak için sizi Boost.Nowide kitaplığına (henüz resmi olarak bir destek değil) yönlendiriyorlar.

Lütfen cevabımın sadece std::basic_string<T> gibi mevcut C++ standart kitaplık sınıflarının çalışma şeklinin bir açıklaması olduğunu unutmayın. UTF-8, Unicode ya da başka bir şeye karşı bir tavsiye değildir. Bildirilen manifesto, bu şeylerin basitçe bu şekilde çalışmadığını ve UTF-8'i herhangi bir yerde kullanmak istediğinizde başka bir şeye ihtiyacınız olduğunu kabul eder.

+1

“bellekte dizelerin UTF-8'de depolanması amaçlanmamıştır. ”- Hayır. Burada yanılıyorsunuz. [UTF-8 Anywhere manifestosu] (http://www.utf8everywhere.org/) sizinle aynı fikirde değil ve bu belge birçok geliştirici tarafından oldukça iyi bir özet olarak görülüyor. Özetle, std :: string' UTF-8 için iyi bir kapsayıcıdır ve standart kütüphane, altta yatan karakter tipine bakılmaksızın, Unicode ile çalışmak için yeterli olanakları sunmaz. –

+0

'std :: string', çok baytlı karakter kümeleri için tasarlanmamıştır, yalnızca bu kadar basittir. Bu tasarıma katılmıyor ve MBCS'nin farkında olduğu alternatif bir dize sınıfı yaratabilirsiniz, ancak 'std :: string' basitçe bu şekilde çalışmaz. Standart kitaplıktaki her şey, tüm karakterlerin aynı sayıda bit içinde kodlandığını varsayar. "Bellek dizeleri UTF-8'de saklanmayı amaçlamıyor" dediğimde, özellikle "std :: string", "std :: wstring" ve underling template class std: : basic_string '. "Substring yöntemleri mutlu bir şekilde geçersiz bir dize döndürecektir" – legalize

+1

Standart kütüphane metinle uğraşmak için yeterli değildir, tasarımından hiçbir yararı yoktur. std :: string' bir bayt depolamadır, metin depolama değildir. Ancak, kodlama agnostik bir şekilde çalışmadığınız sürece, "std :: string" işlevini UTF-8 kodlu metin için şeffaf bir depolama alanı olarak kullanmak tamamen uygundur. Bunun için ICU veya [Ogonek] (http://flamingdangerzone.com/ogonek/) gibi bir kütüphaneye (son derece hoş C++ arayüzüne sahip ancak hala eksik olan) ihtiyacınız olacaktır. –

İlgili konular