Menü
ücretsiz
Kayıt
Ev  /  Donanım yazılımı/ PHP ve Python'da metin kodlamanın tanımı. PHP Metin Kodlama Belirleme - Mevcut Çözümlere Genel Bakış Artı Başka Bir Bisiklet PHP Ne Olacak?

PHP ve Python'da metin kodlamasını belirleme. PHP Metin Kodlama Belirleme - Mevcut Çözümlere Genel Bakış Artı Başka Bir Bisiklet PHP Ne Olacak?

Bir sorun vardı: UTF-8'e göre bir metin dizesinin kodlamasının hızlı bir şekilde nasıl belirleneceği Giderek artan bir şekilde, UNICODE kodlamasında dizelerle çalışmak zorundasınız.

Aşağıda, UNICODE (UTF-8) kodlamasının WINDOWS (win-1251) kodlamasına dönüştürülmesi gerekip gerekmediğini kontrol eden bir işlev bulunmaktadır.

İşlev, kod karakter dönüştürme üzerine inşa edilmemiş olmasına rağmen oldukça doğru bir yanıt verir.

işlev tespit_my_utf($s)( $s=urlencode($s); // bazı durumlarda ekstra işlem (yorumlayın) $res="0"; $j=strlen($s); $s2=strtoupper($s ) ; $s2=str_replace("%D0","",$s2); $s2=str_replace("%D1","",$s2); $k=strlen($s2); $m=1; if ($k>0)( $m=$j/$k; if (($m>1.2)&&($m)

Kısaca - işlevin açıklaması tespit_my_utf():

  • dönüştürmek (dizeyi özel biçime)
  • giriş dizesinin uzunluğunu hesapla
  • bir dizideki tüm harfleri büyük harfe çevir
  • %D0 ve %D1 özel kodlarını kaldır
  • yeni dizenin uzunluğunu hesapla
  • eski çizginin yenisine oranını al

Bu oran 1 veya ona yakınsa, gelen dizgenin UNICODE'da kodlanmadığına dair bir şüphe vardır. Bu oran 1,2 ila 2,2 aralığındaysa, diziyi WINDOWS kodlaması win-1251'e güvenli bir şekilde yeniden kodlayabilirsiniz.

Fonksiyonun çıktısında UNICODE veya UNICODE değil, sırasıyla 0 veya 1 var.

İşlev yürütme örnekleri:

Giriş dizisi: R°R?RyoR?R°S+RyoRyo R? imageready Dönüştürülen dizi: %D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA %D1%81%D0%BE%D0%B7%D0%B4%D0 %B0%D0%BD%D0%B8%D1%8F %D0%B0%D0%BD%D0%B8%D0%BC%D0%B0%D1%86%D0%B8%D0%B8%20%D0 %B2 imageready Fonksiyonun sonucu: 1 Kodlanmış tümcecik: imageready'de animasyon nasıl oluşturulur

Giriş dizisi: R?C?R?R?R?C

Giriş dizisi:

Giriş dizisi: çizim kılavuzu Dönüştürülmüş dizi: %EF%EE%F1%EE%E1%E8%E5 %EF%EE %F0%E8%F1%EE%E2%E0%ED%E8%FE Fonksiyon sonucu: 0 Kodlanmış Cümle : Çizim Eğitimi Bu algoritma, bir arama motoru dönüşüm istatistikleri hizmetinin bir parçası olarak çeşitli gelen dizelerle iyi çalışır.

Sitedeki ilginç materyaller:

  • Sitenin arama ilgisi hakkında bir makale. Belki bazı materyaller 10 yıldır modası geçmiş, ancak bazı noktalara dikkat etmeye değer.

  • Verici site ile alıcı siteler arasında hiper bağlantı alışverişi sorununa ilişkin görüşünüz.

  • Başka bir hayat hilesi. "Balda" oyununda dürüst olmayan oyuncuları yendik. Kolayca genişletilebilen geniş sözcük veritabanı.

Görevle karşı karşıya - sayfanın/metnin/kodlama ne olursa olsun otomatik algılama. Görev yeni değil ve birçok bisiklet zaten icat edildi. Makale, internette bulunanlara dair küçük bir genel bakış içeriyor - artı bana göre değerli bir çözüm olan kendi teklifim.

1. Neden mb_detect_encoding() olmasın?

Kısacası çalışmıyor.

Hadi izleyelim:
// Girişte - CP1251 ile kodlanmış Rusça metin $string = iconv("UTF-8", "Windows-1251", "Anna Pavlovna'ya yaklaştı, elini öptü, ona parfümlü ve parlak kel kafasını uzattı ve sakince oturdu. kanepede."); // md_detect_encoding()'in bize ne verdiğine bakalım. İlk $strict = FALSE var_dump(mb_detect_encoding($string, array("UTF-8"))); // UTF-8 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251"))); // Windows-1251 var_dump(mb_detect_encoding($string, array("UTF-8", "KOI8-R"))); // KOI8-R var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R"))); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"))); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"))); // ISO-8859-5 // Şimdi $strict = TRUE var_dump(mb_detect_encoding($string, array("UTF-8"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "KOI8-R"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R"), DOĞRU)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"), DOĞRU)); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"), DOĞRU)); // ISO-8859-5
Gördüğünüz gibi çıktı tam bir karmaşa. Bir fonksiyonun neden bu şekilde davrandığını anlamadığımızda ne yaparız? Bu doğru, Google'dayız. Harika bir cevap buldum.

Sonunda mb_detect_encoding() kullanımına ilişkin tüm umutları ortadan kaldırmak için mbstring uzantısının kaynaklarına girmeniz gerekir. O halde kolları sıvayın, başlayalım:
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // satır 2703 ret = mbfl_identify_encoding_name(&string, elist, boyut, katı); ...
Ctrl+tıklama:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:643 const char* mbfl_identify_encoding_name(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int solid) ( const mbfl_encoding *kodlama; kodlama = mbfl_identify_encoding(string, elist, elistsz) , sıkı); ...
Ctrl+tıklama:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * kodlamayı tanımlayın */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int solid) ( ...
postalamak tam metin Makaleyi gereksiz kaynaklarla tıkamamak için yöntemi kullanmayacağım. Merak edenler kendileri görecektir. Karakterin kodlamaya uyup uymadığının gerçekten kontrol edildiği 593 numaralı satırla ilgileneceğiz:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, filter); if (filtre->flag) ( bad++; )
Tek baytlık Kiril için ana filtreler şunlardır:

Windows-1251 (orijinal yorumlar saklandı)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* bunların hepsi artık çok çirkin! */ static int mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c)< 0xff) filter->bayrak = 0; başka filtre->

KOI8-R
// ext/mbstring/libmbfl/filters/mbfilter_koi8r.c:142 static int mbfl_filt_ident_koi8r(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c)< 0xff) filter->bayrak = 0; başka filtre->işaret = 1; /* değil */ dönüş c; )

ISO-8859-5 (burada her şey genellikle eğlencelidir)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *filter) ( dönüş c; )
Gördüğünüz gibi, ISO-8859-5 her zaman DOĞRU döndürür (YANLIŞ döndürmek için filter->flag = 1 ayarlamanız gerekir).

Filtrelere baktığımızda her şey yerli yerine oturdu. CP1251, KOI8-R'den ayırt edilemez. Genel olarak ISO-8859-5, kodlamalar listesinde yer alıyorsa her zaman doğru olarak algılanacaktır.

Genel olarak, başarısız. Anlaşılabilir - bu kodlar farklı kodlamalarda kesiştiğinden, genel durumda yalnızca karakter kodlarıyla kodlamayı bulmak imkansızdır.

2. Google'ın sundukları

Ve Google her türlü sefalet verir. Kaynağı buraya bile koymayacağım, isterseniz kendiniz görün (http://'den sonraki boşluğu kaldırın, metni bağlantı olarak değil nasıl göstereceğimi bilmiyorum):

http://deer.org.ua/2009/10/06/1/
http://php.su/forum/topic.php?forum=1&topic=1346

3. Haber arama

1) tekrar karakter kodları: habrahabr.ru/blogs/php/27378/#comment_710532

2) bence çok ilginç bir çözüm: habrahabr.ru/blogs/php/27378/#comment_1399654
Bağlantıdaki yorumlarda artıları ve eksileri. Şahsen, bu çözümün yalnızca kodlama tespiti için gereksiz olduğunu düşünüyorum - çok güçlü olduğu ortaya çıktı. İçindeki kodlamanın tanımı - bir yan etki olarak).

4. Aslında benim kararım

Fikir, önceki bölümdeki ikinci bağlantıyı görüntülerken ortaya çıktı. Fikir şu: Büyük bir Rusça metin alıyoruz, farklı harflerin frekanslarını ölçüyoruz ve bu frekansları kodlamayı tespit etmek için kullanıyoruz. İleriye baktığımda, büyük ve küçük harflerle ilgili sorunlar olacağını hemen söyleyeceğim. Bu nedenle, hem büyük/küçük harfe duyarlı hem de büyük/küçük harfe duyarlı olmayan harf frekanslarının örneklerini (buna "spektrum" diyelim) gönderiyorum (ikinci durumda, küçük harfe aynı frekansla daha da büyük bir harf ekledim ve tüm büyük harfleri sildim). Bu "spektrumlarda", frekansı 0,001'den az olan tüm harfler ve bir boşluk kesilir. İşte "Savaş ve Barış"ı işledikten sonra elde ettiklerim:

Büyük/küçük harfe duyarlı "spektrum":
dizi("o" => 0,095249209893009, "e" => 0,06836817536026, "a" => 0,067481298384992, "u" => 0,055995027400041, "n" => 0,052242744063325, ... . "e" => 0,002252892226507, "N " => 0,0021318391371162, "P" => 0,0018574762967903, "f" => 0,0015961610948418, "V" => 0,0014044332975731, "O" => 0,0013188987793209 , "A" => 0,0012623590130186, "K" => 0,0011804488387602, "M" => 0,001061932790165,)

Büyük/küçük harf duyarsız:
array("O" => 0,095249209893009, "o" => 0,095249209893009, "E" => 0,06836817536026, "e" => 0,06836817536026, "A" => 0,067481298384992, "a " => 0,067481298384992, "VE" => 0,055995027400041 , "i" => 0,055995027400041, .... "C" => 0,0029893589260344, "c" => 0,0029893589260344, "u" => 0,0024649163501406, "u" => 0,00246491635 01406, "E" => 0,002252892226507, "e " => 0,002252892226507, "Ф" => 0,0015961610948418, "Ф" => 0,0015961610948418,)

Farklı kodlamalardaki spektrumlar (dizi tuşları - karşılık gelen kodlamada karşılık gelen karakterlerin kodları):

Daha öte. Bilinmeyen bir kodlamanın metnini alıyoruz, kontrol ettiğimiz her kodlama için o anki karakterin frekansını buluyor ve bu kodlamayı "derecelendirmeye" ekliyoruz. En yüksek derecelendirmeye sahip kodlama, büyük olasılıkla metin kodlamasıdır.

$encodings = array("cp1251" => "specter_cp1251.php", "koi8r" => "specter_koi8r.php", "iso88595" => "specter_iso88595.php" gerektirir); $enc_rates = dizi(); için ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ( $enc_rates[$kodlama] += $char_specter)]; ) var_dump($enc_rates);
Bu kodu kendi başınıza çalıştırmayı denemeyin bile - işe yaramaz. Bunu sözde kod olarak düşünebilirsiniz - Makaleyi karıştırmamak için ayrıntıları atladım. $char_specter, yalnızca pastebin'de başvurulan dizilerdir.

sonuçlar
Tablonun satırları metin kodlamasıdır, sütunlar $enc_rates dizisinin içeriğidir.

1) $str = "Rusça metin";
0,441 | 0,020 | 0,085 | Windows-1251
0,049 | 0,441 | 0,166 | KOI8-R
0,133 | 0,092 | 0,441 | ISO-8859-5

Herşey yolunda. Gerçek kodlama zaten diğerlerinden 4 kat daha yüksek derecelendirmeye sahip - bu çok kısa bir metinde. Daha uzun metinler için oran yaklaşık olarak aynı olacaktır.


cp1251 | koi8r | iso88595 |
0,013 | 0,705 | 0,331 | Windows-1251
0,649 | 0,013 | 0,201 | KOI8-R
0,007 | 0,392 | 0,013 | ISO-8859-5

Hay aksi! Tam yulaf lapası. Çünkü CP1251'deki büyük harfler genellikle KOI8-R'deki küçük harflere karşılık gelir. Ve sırayla küçük harfler büyük harflerden çok daha sık kullanılır. Bu nedenle CP1251'deki büyük harf dizisini KOI8-R olarak tanımlıyoruz.
Bunu büyük/küçük harfe duyarsız yapmaya çalışmak (“spektra” büyük/küçük harfe duyarsız)

1) $str = "Rusça metin";
cp1251 | koi8r | iso88595 |
0,477 | 0,342 | 0,085 | Windows-1251
0,315 | 0,477 | 0,207 | KOI8-R
0,216 | 0,321 | 0,477 | ISO-8859-5

2) $str = "STRING CAPSOM RUSÇA METİN";
cp1251 | koi8r | iso88595 |
1.074 | 0,705 | 0,465 | Windows-1251
0,649 | 1.074 | 0,201 | KOI8-R
0,331 | 0,392 | 1.074 | ISO-8859-5

Gördüğünüz gibi, doğru kodlama tutarlı bir şekilde hem büyük/küçük harfe duyarlı “spektra” (dize az sayıda büyük harf içeriyorsa) hem de büyük/küçük harfe duyarlı olmayanlara yol açar. İkinci durumda, büyük/küçük harfe duyarsız olanlarda, lider elbette o kadar emin değil, ancak küçük dizilerde bile oldukça kararlı. Harflerin ağırlıklarıyla da oynayabilirsiniz - örneğin, frekansa göre onları doğrusal olmayan hale getirin.

5. Sonuç

Konu, UTF-8 ile çalışmayı kapsamıyor - burada karakter kodlarını almanın ve dizgiyi karakterlere bölmenin biraz daha uzun / daha karmaşık olması dışında temel bir fark yok.
Bu fikirler elbette sadece Kiril kodlamalarına genişletilemez - soru sadece karşılık gelen dillerin / kodlamaların "spektrasında".

Not: Çok gerekli / ilginçse, tam olarak çalışan bir kitaplığın ikinci bölümünü GitHub'da yayınlayacağım. Gönderideki verilerin böyle bir kitaplığı hızlı bir şekilde yazmak ve kendi ihtiyaçlarınızı karşılamak için oldukça yeterli olduğuna inansam da - Rus dili için "spektrum" düzenlenmiştir, gerekli tüm kodlamalara kolayca aktarılabilir.

Fikir - Piyango

Kodlamayı alma fikrini bulamadım ama maalesef yazara da söyleyemem, çünkü yaklaşık 4 yıl önceydi ve bu bilgiyi nereden aldığım çoktan unutulmuştu. Yazar, tanımın bir varyantını önerdi ve Python dilinde 1-2 kodlama için bir örnek gösterdi. Çözümünün basitliği beni bir yana bırakmadı ve onu istenen sonuca kadar geliştirdim.
Fikrin özü, kodlama tablolarının kendisinde yatmaktadır. Bildiğiniz gibi, herhangi bir kodlama kendi kod tablosunu içerir ve kodlamanın her karakterine belirli bir değer atanır. Burada kodlama tablolarını göstermeyeceğim, artık bunları internette bulmak oldukça kolay.
Uygulama ilkesi aşağıdaki gibidir:
  1. Kontrol edilen metnin "analizinin" sonucunu depolamak için bir dizi değişkeni oluşturulur. Her dizi öğesi, belirli bir kodlamanın sonucunu içerecektir.
  2. Fonksiyon girişinde alınan metin karakter karakter sıralanır.
  3. Her karakterden bir sıra (o karakterin değeri) alınır ve kodlama aralığıyla karşılaştırılır.
  4. Değer bir büyük harf (büyük harf) karakterinin üzerine düşerse, bu kodlamanın sonucunu saklayan dizi elemanı 1 olarak ayarlanır.
  5. Değer küçük harfli (küçük) bir karaktere düşerse, bu kodlamanın sonucunu saklayan dizi öğesi 3 olarak ayarlanır.
  6. Bu kodlama, daha doğrusu, dizinin kodlamasının sonucunu depolayan ve en çok puan alan öğesi, büyük olasılıkla orijinal kodlamadır.
Bu algoritma, KOI-8, CP1251 (windows-1251) ve diğerleri gibi tek baytlık kodlamalar için geçerlidir. Ancak, çift baytlık kodlamalar için (benim durumumda UTF-8), bu yaklaşım hatalı bir sonuç verecektir. Başlangıç ​​olarak büyük harf için 5, küçük harf için 7 ekleyerek bu sorunu çözmeye çalıştım sonuç daha iyi oldu ama yine de tanıma hataları vardı. Bazı deneylerden sonra, UTF'nin doğru tanımı için büyük harflerle sonuca 10 eklenmesi gerektiği sonucuna vardım, küçük harf 14 için yani ilk varsayımımın 2 katı. Ancak kodun daha iyi görsel olarak anlaşılması için UTF karakterleri için sırasıyla 5 ve 7 bıraktım ve zaten kontrol sırasında bu değerler 2 artırılarak sonuca eklendi.
Temel olarak tüm algoritma budur. Ve herhangi bir ekstra güçlük olmadan.
Bu işlevin uygulanması için çoğu zaman, elbette, kod tablolarını aramaya ve aralıkların doğru düzenlenmesine harcandı. Bu fonksiyonu ilk yazdığım zaman gerçek kod tablosunu bulmak oldukça zordu, aynı zamanda içlerindeki karakter aralıkları da rastgele atlıyordu. Ancak daha sonra en alakalı (bugüne kadar) kodlamalarda karar kıldım: UTF-8, CP1251, KOI8-R, IBM866, ISO-8859-5 ve MAC. Bu kodlamalar sizin için yeterli değilse, bu algoritma kod ekleyin.

Kelimelerden pratiğe

Aslında, Python'daki tüm işlev kodu şöyle görünür:

Kodlamalar = ( "UTF-8": "utf-8", "CP1251": "windows-1251", "KOI8-R": "koi8-r", "IBM866": "ibm866", "ISO-8859- 5": "iso-8859-5", "MAC": "mac", ) """ Metin kodlama tanımı """ def get_codepage(str = Yok): büyük harf = 1 küçük harf = 3 utfupper = 5 utflower = 7 kod sayfası = () encodings.keys() içindeki enc için: codepages = 0, eğer str Yok değilse ve len(str) > 0: last_simb = 0 str'deki simb için: simb_ord = ord(simb) """rusça olmayan karakterler" "" simb_ord ise< 128 or simb_ord >256: last_simb == 208 ve (143) ise """UTF-8""" ile devam edin< simb_ord < 176 or simb_ord == 129): codepages["UTF-8"] += (utfupper * 2) if (last_simb == 208 and (simb_ord == 145 or 175 < simb_ord < 192)) \ or (last_simb == 209 and (127 < simb_ord < 144)): codepages["UTF-8"] += (utflower * 2) """CP1251""" if 223 < simb_ord < 256 or simb_ord == 184: codepages["CP1251"] += lowercase if 191 < simb_ord < 224 or simb_ord == 168: codepages["CP1251"] += uppercase """KOI8-R""" if 191 < simb_ord < 224 or simb_ord == 163: codepages["KOI8-R"] += lowercase if 222 < simb_ord < 256 or simb_ord == 179: codepages["KOI8-R"] += uppercase """IBM866""" if 159 < simb_ord < 176 or 223 < simb_ord < 241: codepages["IBM866"] += lowercase if 127 < simb_ord < 160 or simb_ord == 241: codepages["IBM866"] += uppercase """ISO-8859-5""" if 207 < simb_ord < 240 or simb_ord == 161: codepages["ISO-8859-5"] += lowercase if 175 < simb_ord < 208 or simb_ord == 241: codepages["ISO-8859-5"] += uppercase """MAC""" if 221 < simb_ord < 255: codepages["MAC"] += lowercase if 127 < simb_ord < 160: codepages["MAC"] += uppercase last_simb = simb_ord idx = "" max = 0 for item in codepages: if codepages >max:max = kod sayfaları idx = öğe dönüşü idx
İşlev çağrısı örneği

Baskı kodlamaları

Peki ya PHP

Hazır bir fonksiyonu Python'dan PHP'ye yeniden yazmak zor olmadı. Görünüşte, Python'daki atasından pratik olarak hiçbir farkı yoktur:

/** * Metin kodlamasını tanımla * @param String $text Metin * @return String Metin kodlama */ function get_codepage($text = "") ( if (!empty($text)) ( $utflower = 7; $utfupper = 5; $küçük harf = 3; $büyük harf = 1; $last_simb = 0; $charsets = dizi("UTF-8" => 0, "CP1251" => 0, "KOI8-R" => 0, "IBM866" => 0, "ISO-8859-5" => 0, "MAC" => 0,); for ($a = 0; $a< strlen($text); $a++) { $char = ord($text[$a]); // non-russian characters if ($char<128 || $char>256) devam; // UTF-8 if (($last_simb==208) && (($char>143 && $char)<176) || $char==129)) $charsets["UTF-8"] += ($utfupper * 2); if ((($last_simb==208) && (($char>175 && $karakter<192) || $char==145)) || ($last_simb==209 && $char>127 && $karakter<144)) $charsets["UTF-8"] += ($utflower * 2); // CP1251 if (($char>223 && $karakter<256) || $char==184) $charsets["CP1251"] += $lowercase; if (($char>191 && $char<224) || $char==168) $charsets["CP1251"] += $uppercase; // KOI8-R if (($char>191 && $char<224) || $char==163) $charsets["KOI8-R"] += $lowercase; if (($char>222 && $karakter<256) || $char==179) $charsets["KOI8-R"] += $uppercase; // IBM866 if (($char>159 && $karakter<176) || ($char>223 && $karakter<241)) $charsets["IBM866"] += $lowercase; if (($char>127 && $karakter<160) || $char==241) $charsets["IBM866"] += $uppercase; // ISO-8859-5 if (($char>207 && $char<240) || $char==161) $charsets["ISO-8859-5"] += $lowercase; if (($char>175 && $karakter<208) || $char==241) $charsets["ISO-8859-5"] += $uppercase; // MAC if ($char>221 && $karakter<255) $charsets["MAC"] += $lowercase; if ($char>127 && $karakter<160) $charsets["MAC"] += $uppercase; $last_simb = $char; } arsort($charsets); return key($charsets); } }
İşlev çağrısı örneği

echo get_codepage(file_get_contents("test.txt"));

Likbez veya makinenin çalışmasına müdahale etmeyin

Bu işlevi kilitlenme testi yapmaya çalışmamalısınız. Algoritmadan, girdi olarak ne kadar az metin alırsa, fonksiyonun kodlamayı yanlış tanıma olasılığının o kadar yüksek olduğu açıktır. Öte yandan, Leo Tolstoy'un beslenme ciltleri de mantıklı değil: bu yöntem, 100-200 karakterlik küçük bir cümle ile mükemmel bir iş çıkarıyor. Giriş çağrısı örneklerinde, kodlamasının belirlenmesi gereken bir metin olduğunu varsayan belirli bir "test.txt" dosyasının tüm içeriğini göndermiş olsam da, küçük bir metin parçası olabilir (ve olmalıdır). fonksiyonun girişine aktarılır.
Karışık büyük ve küçük harflerle yapılan sapkınlıklar, bu durumda genellikle uygun değildir, çünkü bu yöntem, yaklaşık olarak okuryazar Rusça ile sıradan bir görev için yazılmıştır. Ve bu tür deneyler bana çoğu zaman bir şakayı hatırlatır:

Bir Rus ağaç işleme tesisi, bir Japon makinesi satın aldı. Rus işçiler onun etrafında toplandı ve nasıl çalıştığını çözelim. Biri tahtayı aldı, içine koydu. Ünite: zzzzzzzzzzzzzzzzin ... Çıkışta hazır tabure. Çocuklar: Kendi başına hiçbir şey!!! Ekrandaki birim: peki, ne düşündün? Bir başkası yontulmamış bir kütüğü alıp üniteye yerleştirdi. Ünite: zzzzzzzzzzzzzzz... Çıkışta oymalı büfe hazır. Çocuklar: Kendi başına hiçbir şey!!! Ekrandaki birim: peki, ne düşündün? Üçüncü adam dayanamayıp bir yerden rayı çekip üniteye taktı. Birim: drrrrr-tyh-tyh-tyh ... İçti ve ekrandaki yazı: Kendi başına hiçbir şey yok !!! Çocuklar: Peki, ne düşündün!
Dolayısıyla, bu tür sapkın testler için, büyük olasılıkla bu işlevin olmadığı bir sapkın algoritmaya ihtiyacınız olacak. Ve uygulamadan şunu söyleyeceğim, 4 yıllık kullanım sırasında bu yöntem beni asla yarı yolda bırakmadı ve her zaman doğru sonucu verdi.
Umarım makalem birileri için faydalı olur.
İlginiz için teşekkür ederiz.

İçeriğin tamamını veya bir kısmını kullanırken kaynağa yani bloguma link vermeyi unutmayınız.

Görevle karşı karşıya - sayfanın/metnin/kodlama ne olursa olsun otomatik algılama. Görev yeni değil ve birçok bisiklet zaten icat edildi. Makale, internette bulunanlara dair küçük bir genel bakış içeriyor - artı bana göre değerli bir çözüm olan kendi teklifim.

1. Neden mb_detect_encoding() olmasın?

Kısacası çalışmıyor.

Hadi izleyelim:
// Girişte - CP1251 ile kodlanmış Rusça metin $string = iconv("UTF-8", "Windows-1251", "Anna Pavlovna'ya yaklaştı, elini öptü, ona parfümlü ve parlak kel kafasını uzattı ve sakince oturdu. kanepede."); // md_detect_encoding()'in bize ne verdiğine bakalım. İlk $strict = FALSE var_dump(mb_detect_encoding($string, array("UTF-8"))); // UTF-8 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251"))); // Windows-1251 var_dump(mb_detect_encoding($string, array("UTF-8", "KOI8-R"))); // KOI8-R var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R"))); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"))); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"))); // ISO-8859-5 // Şimdi $strict = TRUE var_dump(mb_detect_encoding($string, array("UTF-8"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "KOI8-R"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R"), DOĞRU)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"), DOĞRU)); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"), DOĞRU)); // ISO-8859-5
Gördüğünüz gibi çıktı tam bir karmaşa. Bir fonksiyonun neden bu şekilde davrandığını anlamadığımızda ne yaparız? Bu doğru, Google'dayız. Harika bir cevap buldum.

Sonunda mb_detect_encoding() kullanımına ilişkin tüm umutları ortadan kaldırmak için mbstring uzantısının kaynaklarına girmeniz gerekir. O halde kolları sıvayın, başlayalım:
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // satır 2703 ret = mbfl_identify_encoding_name(&string, elist, boyut, katı); ...
Ctrl+tıklama:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:643 const char* mbfl_identify_encoding_name(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int solid) ( const mbfl_encoding *kodlama; kodlama = mbfl_identify_encoding(string, elist, elistsz) , sıkı); ...
Ctrl+tıklama:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * kodlamayı tanımlayın */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int solid) ( ...
Makaleyi gereksiz kaynaklarla tıkamamak için yöntemin tam metnini yayınlamayacağım. Merak edenler kendileri görecektir. Karakterin kodlamaya uyup uymadığının gerçekten kontrol edildiği 593 numaralı satırla ilgileneceğiz:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, filter); if (filtre->flag) ( bad++; )
Tek baytlık Kiril için ana filtreler şunlardır:

Windows-1251 (orijinal yorumlar saklandı)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* bunların hepsi artık çok çirkin! */ static int mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c)< 0xff) filter->bayrak = 0; başka filtre->

KOI8-R
// ext/mbstring/libmbfl/filters/mbfilter_koi8r.c:142 static int mbfl_filt_ident_koi8r(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c)< 0xff) filter->bayrak = 0; başka filtre->işaret = 1; /* değil */ dönüş c; )

ISO-8859-5 (burada her şey genellikle eğlencelidir)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *filter) ( dönüş c; )
Gördüğünüz gibi, ISO-8859-5 her zaman DOĞRU döndürür (YANLIŞ döndürmek için filter->flag = 1 ayarlamanız gerekir).

Filtrelere baktığımızda her şey yerli yerine oturdu. CP1251, KOI8-R'den ayırt edilemez. Genel olarak ISO-8859-5, kodlamalar listesinde yer alıyorsa her zaman doğru olarak algılanacaktır.

Genel olarak, başarısız. Anlaşılabilir - bu kodlar farklı kodlamalarda kesiştiğinden, genel durumda yalnızca karakter kodlarıyla kodlamayı bulmak imkansızdır.

2. Google'ın sundukları

Ve Google her türlü sefalet verir. Kaynağı buraya bile koymayacağım, isterseniz kendiniz görün (http://'den sonraki boşluğu kaldırın, metni bağlantı olarak değil nasıl göstereceğimi bilmiyorum):

http://deer.org.ua/2009/10/06/1/
http://php.su/forum/topic.php?forum=1&topic=1346

3. Haber arama

1) tekrar karakter kodları:

2) bence çok ilginç bir çözüm:
Bağlantıdaki yorumlarda artıları ve eksileri. Şahsen, bu çözümün yalnızca kodlama tespiti için gereksiz olduğunu düşünüyorum - çok güçlü olduğu ortaya çıktı. İçindeki kodlamanın tanımı - bir yan etki olarak).

4. Aslında benim kararım

Fikir, önceki bölümdeki ikinci bağlantıyı görüntülerken ortaya çıktı. Fikir şu: Büyük bir Rusça metin alıyoruz, farklı harflerin frekanslarını ölçüyoruz ve bu frekansları kodlamayı tespit etmek için kullanıyoruz. İleriye baktığımda, büyük ve küçük harflerle ilgili sorunlar olacağını hemen söyleyeceğim. Bu nedenle, hem büyük/küçük harfe duyarlı hem de büyük/küçük harfe duyarlı olmayan harf frekanslarının örneklerini (buna "spektrum" diyelim) gönderiyorum (ikinci durumda, küçük harfe aynı frekansla daha da büyük bir harf ekledim ve tüm büyük harfleri sildim). Bu "spektrumlarda", frekansı 0,001'den az olan tüm harfler ve bir boşluk kesilir. İşte "Savaş ve Barış"ı işledikten sonra elde ettiklerim:

Büyük/küçük harfe duyarlı "spektrum":
dizi("o" => 0,095249209893009, "e" => 0,06836817536026, "a" => 0,067481298384992, "u" => 0,055995027400041, "n" => 0,052242744063325, ... . "e" => 0,002252892226507, "N " => 0,0021318391371162, "P" => 0,0018574762967903, "f" => 0,0015961610948418, "V" => 0,0014044332975731, "O" => 0,0013188987793209 , "A" => 0,0012623590130186, "K" => 0,0011804488387602, "M" => 0,001061932790165,)

Büyük/küçük harf duyarsız:
array("O" => 0,095249209893009, "o" => 0,095249209893009, "E" => 0,06836817536026, "e" => 0,06836817536026, "A" => 0,067481298384992, "a " => 0,067481298384992, "VE" => 0,055995027400041 , "i" => 0,055995027400041, .... "C" => 0,0029893589260344, "c" => 0,0029893589260344, "u" => 0,0024649163501406, "u" => 0,00246491635 01406, "E" => 0,002252892226507, "e " => 0,002252892226507, "Ф" => 0,0015961610948418, "Ф" => 0,0015961610948418,)

Farklı kodlamalardaki spektrumlar (dizi tuşları - karşılık gelen kodlamada karşılık gelen karakterlerin kodları):

Daha öte. Bilinmeyen bir kodlamanın metnini alıyoruz, kontrol ettiğimiz her kodlama için o anki karakterin frekansını buluyor ve bu kodlamayı "derecelendirmeye" ekliyoruz. En yüksek derecelendirmeye sahip kodlama, büyük olasılıkla metin kodlamasıdır.

$encodings = array("cp1251" => "specter_cp1251.php", "koi8r" => "specter_koi8r.php", "iso88595" => "specter_iso88595.php" gerektirir); $enc_rates = dizi(); için ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ( $enc_rates[$kodlama] += $char_specter)]; ) var_dump($enc_rates);
Bu kodu kendi başınıza çalıştırmayı denemeyin bile - işe yaramaz. Bunu sözde kod olarak düşünebilirsiniz - Makaleyi karıştırmamak için ayrıntıları atladım. $char_specter, yalnızca pastebin'de başvurulan dizilerdir.

sonuçlar
Tablonun satırları metin kodlamasıdır, sütunlar $enc_rates dizisinin içeriğidir.

1) $str = "Rusça metin";
0,441 | 0,020 | 0,085 | Windows-1251
0,049 | 0,441 | 0,166 | KOI8-R
0,133 | 0,092 | 0,441 | ISO-8859-5

Herşey yolunda. Gerçek kodlama zaten diğerlerinden 4 kat daha yüksek derecelendirmeye sahip - bu çok kısa bir metinde. Daha uzun metinler için oran yaklaşık olarak aynı olacaktır.


cp1251 | koi8r | iso88595 |
0,013 | 0,705 | 0,331 | Windows-1251
0,649 | 0,013 | 0,201 | KOI8-R
0,007 | 0,392 | 0,013 | ISO-8859-5

Hay aksi! Tam yulaf lapası. Çünkü CP1251'deki büyük harfler genellikle KOI8-R'deki küçük harflere karşılık gelir. Ve sırayla küçük harfler büyük harflerden çok daha sık kullanılır. Bu nedenle CP1251'deki büyük harf dizisini KOI8-R olarak tanımlıyoruz.
Bunu büyük/küçük harfe duyarsız yapmaya çalışmak (“spektra” büyük/küçük harfe duyarsız)

1) $str = "Rusça metin";
cp1251 | koi8r | iso88595 |
0,477 | 0,342 | 0,085 | Windows-1251
0,315 | 0,477 | 0,207 | KOI8-R
0,216 | 0,321 | 0,477 | ISO-8859-5

2) $str = "STRING CAPSOM RUSÇA METİN";
cp1251 | koi8r | iso88595 |
1.074 | 0,705 | 0,465 | Windows-1251
0,649 | 1.074 | 0,201 | KOI8-R
0,331 | 0,392 | 1.074 | ISO-8859-5

Gördüğünüz gibi, doğru kodlama tutarlı bir şekilde hem büyük/küçük harfe duyarlı “spektra” (dize az sayıda büyük harf içeriyorsa) hem de büyük/küçük harfe duyarlı olmayanlara yol açar. İkinci durumda, büyük/küçük harfe duyarsız olanlarda, lider elbette o kadar emin değil, ancak küçük dizilerde bile oldukça kararlı. Harflerin ağırlıklarıyla da oynayabilirsiniz - örneğin, frekansa göre onları doğrusal olmayan hale getirin.

5. Sonuç

Konu, UTF-8 ile çalışmayı kapsamıyor - burada karakter kodlarını almanın ve dizgiyi karakterlere bölmenin biraz daha uzun / daha karmaşık olması dışında temel bir fark yok.
Bu fikirler elbette sadece Kiril kodlamalarına genişletilemez - soru sadece karşılık gelen dillerin / kodlamaların "spektrasında".

Not: Çok gerekli / ilginçse, tam olarak çalışan bir kitaplığın ikinci bölümünü GitHub'da yayınlayacağım. Gönderideki verilerin böyle bir kitaplığı hızlı bir şekilde yazmak ve kendi ihtiyaçlarınızı karşılamak için oldukça yeterli olduğuna inansam da - Rus dili için "spektrum" düzenlenmiştir, gerekli tüm kodlamalara kolayca aktarılabilir.

Farklı RSS beslemelerinden birçok metin okudum ve bunları veritabanıma ekledim.

Tabii ki, kanallarda kullanılan birkaç farklı karakter kodlaması vardır, örn. UTF-8 ve ISO-8859-1.

Ne yazık ki, bazen metin kodlamalarında sorunlar olabilir. Örnek:

1) "Fußball"daki "ß" veritabanımda şöyle görünmelidir: "Ÿ". "Ÿ" ise, doğru görüntüler.

2) Bazen "Fußball"daki "ß" veri tabanımda şuna benziyor: "ß". O zaman elbette yanlış gösteriliyor.

3) Diğer durumlarda, "ß", "ß" olarak saklanır - yani herhangi bir değişiklik yapılmaz. Sonra da yanlış görüntüler.

2. ve 3. durumlardan kaçınmak için ne yapabilirim?

Her şeyi aynı kodlamayı, tercihen UTF-8'i nasıl yapabilirim? utf8_encode()'u ne zaman kullanmalıyım, ne zaman utf8_decode()'u kullanmalıyım (efektin ne olduğu açık, ancak işlevleri ne zaman kullanmalıyım?) ve girdiyle ne zaman bir şey yapmalıyım?

Bana yardım edip aynı kodlamayı nasıl yapacağımı söyler misin? Belki de mb-detect-encoding() işleviyle? Bunun için bir fonksiyon yazabilir miyim? Bu yüzden benim sorunlarım: 1) Metinde hangi kodlamanın kullanıldığını nasıl öğrenebilirim 2) Eski kodlamadan bağımsız olarak UTF-8'e nasıl dönüştürebilirim?

DÜZENLEMEK: Böyle bir işlev işe yarar mı?

function correct_encoding($text) ( $current_encoding = mb_detect_encoding($text, "auto"); $text = iconv($current_encoding, "UTF-8", $text); return $text; )

Test ettim ama çalışmıyor. O'nun nesi var?

24 cevap

Zaten var olan bir UTF8 dizgisine utf8_encode() uygularsanız, karıştırılmış UTF8 çıktısı döndürür.

Tüm bu sorunları gideren bir işlev yarattım. Buna Encoding::toUTF8() denir.

Dizelerinizin kodlamasının ne olduğunu bilmenize gerek yok. Latin1 (iso 8859-1), Windows-1252 veya UTF8 olabilir veya dize bunları içerebilir. Encoding::toUTF8() her şeyi UTF8'e dönüştürür.

Bunu yaptım çünkü hizmet bana UTF8 ve Latin1'i aynı satırda karıştıran, hepsi karışık bir veri akışı veriyordu.

kullanım:

Require_once("Kodlama.php"); \ForceUTF8\Encoding'i kullanın; // Şimdi isim alanı eklendi. $utf8_string = Kodlama::toUTF8($utf8_or_latin1_or_mixed_string); $latin1_string = Kodlama::toLatin1($utf8_or_latin1_or_mixed_string);

Bozuk görünen her UTF8 dizgisini düzeltecek başka bir işlev olan Encoding::fixUFT8() ekledim.

kullanım:

Require_once("Kodlama.php"); \ForceUTF8\Encoding'i kullanın; // Şimdi isim alanı eklendi. $utf8_string = Kodlama::fixUTF8($garbled_utf8_string);

Echo Encoding::fixUTF8("Fédération Camerounaise de Football"); echo Encoding::fixUTF8("Fédération Camerounaise de Football"); echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football"); echo Encoding::fixUTF8("Futbol Futbol Federasyonu");

Kamerun Futbol Federasyonu Kamerun Futbol Federasyonu Kamerun Futbol Federasyonu Kamerun Futbol Federasyonu Kamerun Futbol Federasyonu

Güncelleme: İşlevi (forceUTF8), Encoding sınıfındaki bir statik işlevler ailesine dönüştürdüm. Yeni özellik- Kodlama::toUTF8().

Öncelikle hangi kodlamanın kullanıldığını belirlemeniz gerekir. RSS yayınlarını (belki HTTP üzerinden) ayrıştırdığınız için, HTTP başlığının Content-Type alanının karakter kümesi parametresinden kodlamayı okumalısınız. Eksikse, işleme talimatının encoding niteliğinden kodlamayı okuyun. Bu da eksikse, teknik özelliklerde tanımlandığı şekilde UTF-8 kullanın.

Değiştirmekİşte muhtemelen yapacağım şey:

Kodlama tespiti zordur.

mb_detect_encoding, geçtiğiniz birden fazla aday arasından tahminde bulunarak çalışır. Bazı kodlamalarda, belirli bayt dizileri geçersizdir, bu nedenle farklı adaylar arasında ayrım yapabilir. Ne yazık ki, aynı baytların geçerli olduğu (ancak farklı) birçok kodlama vardır. Bu durumlarda kodlamayı belirlemek mümkün değildir; Bu durumlarda tahminlerde bulunmak için kendi mantığınızı uygulayabilirsiniz. Örneğin, bir Japon sitesinden gelen verilerin Japonca kodlaması olması muhtemeldir.

Yalnızca Batı Avrupa dilleriyle uğraşırken, üç ana kodlamayı göz önünde bulundurun: utf-8 , iso-8859-1 ve cp-1252 . Birçok platform için varsayılan olduklarından, yanlış raporlanmaları da olasıdır. Örneğin. insanlar farklı kodlamalar kullanırsa, muhtemelen bu konuda açık sözlü olacaklardır çünkü aksi halde onların yazılımçok sık kırılacaktır. Bu nedenle, kodlama bu üçünden biri olarak bildirilmedikçe, sağlayıcıya güvenmek iyi bir stratejidir. Yine de mb_check_encoding kullanarak gerçekten geçerli olduğunu ikiye katlamalısınız (geçerli olmanın olmakla aynı olmadığını unutmayın - aynı girdi birçok kodlama için geçerli olabilir). Onlardan biriyse, ayırt etmek için mb_detect_encoding'i kullanabilirsiniz. Neyse ki, bu oldukça belirleyicidir; UTF-8,ISO-8859-1,WINDOWS-1252 olan doğru algılama sırasını kullanmanız yeterlidir.

Kodlamayı bulduğunuzda, onu dahili temsiline dönüştürmeniz gerekir (yalnızca utf-8 akıllı seçim). utf8_encode işlevi, iso-8859-1'i utf-8'e dönüştürür, böylece yalnızca söz konusu giriş türü için kullanılabilir. Diğer kodlamalar için mb_convert_encoding kullanın.

Bu kopya kağıdı, PHP'nin UTF-8'i işlemesiyle ilgili bazı yaygın uyarıları listeler: http://developer.loftdigital.com/blog/php-utf-8-cheatsheet

Bir dizgedeki çok baytlı karakterleri algılayan bu işlev ayrıca yararlı olabilir ():

findUTF8($string) işlevi ( return preg_match("%(?: [\xC2-\xDF][\x80-\xBF] # aşırı uzun olmayan 2 bayt |\xE0[\xA0-\xBF][\x80-) \xBF] # fazla uzunlar hariç |[\xE1-\xEC\xEE\xEF][\x80-\xBF](2) # düz 3 bayt |\xED[\x80-\x9F][\x80-\xBF] # vekiller hariç |\xF0[\x90-\xBF][\x80-\xBF](2) # düzlemler 1-3 |[\xF1-\xF3][\x80-\xBF](3) # düzlemler 4- 15 |\xF4[\x80-\x8F][\x80-\xBF](2) # düzlem 16)+%xs", $string); )

Biraz uyarı, veritabanınızda "ß"nin "Ÿ" olarak görünmesi gerektiğini söylediniz.

Muhtemelen latin1 karakter kodlamasına sahip bir veritabanı kullandığınızdan veya php-mysql bağlantısının yanlış yapılandırıldığından, php, mysql'inizin utf-8 kullanmaya ayarlı olduğunu düşünür, bu nedenle verileri utf8 olarak gönderir, ancak mysql'iniz php'nin veri gönderdiğine inanır. iso-8859-1 olarak kodlanmıştır, bu nedenle gönderdiğiniz verileri tekrar utf-8 olarak kodlamaya çalışabilir ve bu gibi sorunlara neden olabilir.

Şuna bir göz atın, size yardımcı olabilir: http://php.net/manual/en/function.mysql-set-charset.php

Yanıtlar farklı kodlamalarla kodlanabileceğinden girişteki kodlamayı kontrol etmeniz gerekir.
Aşağıdaki işlevi kullanarak algılama ve çeviri yaparak tüm içeriğin UTF-8'de gönderilmesini zorluyorum:

function fixRequestCharset() ( $ref = array(&$_GET, &$_POST, &$_REQUEST); foreach ($ref as &$var) ( foreach ($var as $key => $val) ( $encoding = mb_detect_encoding ($var[ $key ], mb_detect_order(), true); if (!$encoding) devam ediyor; if (strcasecmp($encoding, "UTF-8") != 0) ( $encoding = iconv($encoding, " UTF-8", $var[ $key ]); if ($encoding === false) devam ediyor; $var[ $key ] = $encoding; ) ) ) )

Bu prosedür her şeyi değiştirecek PHP değişkenleri UTF-8'deki uzak ana bilgisayardan gelen.
Veya kodlama algılanamıyor veya dönüştürülemiyorsa değeri yok sayın.
İhtiyaçlarınıza göre özelleştirebilirsiniz.
Değişkenleri kullanmadan önce aramanız yeterlidir.

Kodlamanız UTF-8 ile kodlanmış gibi görünüyor iki kere; yani başka bir kodlamadan UTF-8'e ve tekrar UTF-8'e. Sanki iso-8859-1'i iso-8859-1'den utf-8'e dönüştürmüş ve ayrıştırmışsınız gibi Yeni hat UTF-8'e başka bir dönüştürme için iso-8859-1 olarak.

İşte yaptığınız şey için bazı sahte kodlar:

$inputstring = getFromUser(); $utf8string = iconv($current_encoding, "utf-8", $inputstring); $flawedstring = iconv($current_encoding, "utf-8", $utf8string);

Denemelisin:

  • mb_detect_encoding() veya ne kullanmak isterseniz onunla kodlamayı tespit edin
  • UTF-8 ise iso-8859-1'e dönüştürün ve 1. adımı tekrarlayın
  • sonunda UTF-8'e geri dön

"Orta" dönüşümde iso-8859-1 kullandığınızı varsayar. Windows-1252 kullandıysanız, Windows-1252'ye (latin1) dönüştürün. Orijinal kaynak kodlaması önemli değildir; hatalı, ikinci dönüşümde kullandığınız.

Olayla ilgili tahminim bu; bir genişletilmiş ASCII baytı yerine dört bayt elde etmek için biraz daha fazlasını yapabilirsiniz.

Almanca ayrıca iso-8859-2 ve windows-1250 (latin2) kullanır.

RSS beslemesi karakter kodlama geliştirmesi karmaşık görünüyor. Normal web sayfaları bile genellikle kodlamalarını atlar veya yalan söyler.

Böylece, doğru kodlama algılama yolunu kullanmayı deneyebilir ve ardından bir tür otomatik algılamaya (tahmin etme) geri dönebilirsiniz.

Bunun eski bir soru olduğunu biliyorum, ancak faydalı bir cevabın asla zarar vermeyeceğine inanıyorum. Masaüstü uygulamaları, SQLite ve GET/POST değişkenleri arasındaki kodlamamda sorun yaşıyorum. Bir kısmı UTF-8'de, bir kısmı ASCII'de olacak ve işin içine yabancı karakterler girince temelde işler karışacak.

İşte benim çözümüm. GET/POST/REQUEST'inizi düzleştirir (kaçırdım kurabiye, ancak gerekirse bunları ekleyebilirsiniz) işlemeden önce her sayfa yüklemesinde. Başlıkta iyi çalışıyor. PHP, kaynak kodlamayı otomatik olarak belirleyemezse uyarı verir, bu nedenle bu uyarılar @ ile bastırılır.

//veritabanı ile iyi oynamak için değişkenlerimizdeki her şeyi UTF-8'e dönüştürün... //Çift kodlama yapmamamıza yardımcı olması için burada bazı otomatik algılama kullanın... //Kodlama algılanamadığında olası uyarıları @ ile bastırın try ( $process = array(&$_GET, &$_POST, &$_REQUEST); while (list($key, $val) = her($process)) ( foreach ($val as $k => $v) ( unset($process[$key][$k]); if (is_array($v)) ( $process[$key][@mb_convert_encoding($k,"UTF-8","auto")] = $ v; $process = &$process[$key][@mb_convert_encoding($k,"UTF-8","auto")]; ) else ( $process[$key][@mb_convert_encoding($k,"UTF-) 8","auto")] = @mb_convert_encoding($v,"UTF-8","auto"); ) ) ) unset($process); ) catch(Exception $ex)()

AGES ile kodlama çözümlerini inceliyorum ve bu sayfa muhtemelen yıllarca süren aramanın sonu! Bahsettiğiniz önerilerden bazılarını test ettim ve işte notlarım:

Bu benim test dizim:

bu, benim kullanmadığım "yanlış yazılmış" dizesidir. özel özelleştirme onları görmek için karakterler, işlev tarafından dönüştürülür!! Peki bu nedir!

Sayfa yazı tipim UTF-8

INSERT'i bu şekilde yaparsam, veritabanımda muhtemelen Mars'tan gelen bazı karakterler var... bu yüzden onları "aklı başında" UTF-8'e dönüştürmem gerekiyor. utf8_encode()'u denedim ama yine de uzaylı karakterler veri tabanımı işgal ediyordu...

Bu yüzden, 8 numarada yayınlanan forceUTF8 işlevini kullanmayı denedim, ancak DB'de kaydedilen dize şöyle görünüyor:

"yanlış yazılmış" dizesi, bunları görmek için "söme" özel şarkılarına basılmadı, işlev tarafından dönüştürüldü!! Peki bu nedir!

Böylece, bu sayfada biraz daha fazla bilgi toplayarak ve diğer sayfalardaki diğer bilgilerle birleştirerek sorunu şu çözümle çözdüm:

$finallyIDidIt = mb_convert_encoding($string, mysql_client_encoding($resourceID), mb_detect_encoding($string));

Artık veri tabanımda doğru kodlamaya sahip bir dizim var.

Not: Sadece mysql_client_encoding işlevine dikkat edin! Bu işlev, parametre olarak bir kaynak kimliği gerektirdiğinden, veritabanına bağlı olmanız gerekir.

Ama tamam, bu yeniden kodlamayı INSERT'imden önce yapıyorum, bu yüzden benim için sorun değil.

Umarım bu, bu sayfa gibi birinin bana yardımcı olmasına yardımcı olur!

Herkese teşekkürler!

mb_detect_encoding ve mb_convert_encoding ile ilgili ilginç olan şey, önerdiğiniz kodlama sırasının önemli olmasıdır:

// $input aslında UTF-8'dir mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8"); // ISO-8859-9 (YANLIŞ!) mb_detect_encoding($girdi, "UTF-8", "UTF-8, ISO-8859-9"); // UTF-8 (Tamam)

Böylece, beklenen kodlamaları belirtirken belirli bir sıra kullanabilirsiniz. Ancak, bunun güvenilir olmadığını unutmayın.

echo mb_detect_encoding($str, "otomatik");

echo mb_detect_encoding($str, "UTF-8, ASCII, ISO-8859-1");

Sonuçların ne olduğunu gerçekten bilmiyorum, ancak beslemelerinizden bazılarını farklı kodlamalarla almanızı ve mb_detect_encoding'in çalışıp çalışmadığını denemenizi öneririm.

Güncelleme
auto, "ASCII, JIS, UTF-8, EUC-JP, SJIS"in kısaltmasıdır. dizeyi iconv ile utf-8'e dönüştürmek için kullanabileceğiniz algılanan kodlamayı döndürür.

Test etmedim, bu yüzden garanti yok. ve belki daha kolay bir yolu vardır.

Bu sürüm Almanca içindir, ancak $CHARSETS ve $TESTCHARS öğelerini değiştirebilirsiniz.

Class CharsetDetector ( özel statik $CHARSETS = dizi("ISO_8859-1", "ISO_8859-15", "CP850"); özel statik $TESTCHARS = dizi("€", "ä", "Ä", "ö", "Ö", "ü", "Ü", "ß"); genel statik işlev convert($string) ( dönüş self::__iconv($string, self::getCharset($string)); ) genel statik işlev getCharset ($string) ( $normalized = self::__normalize($string); if(!strlen($normalized))return "UTF-8"; $best = "UTF-8"; $charcountbest = 0; foreach (self) ::$CHARSETS as $charset) ( $str = self::__iconv($normalized, $charset); $charcount = 0; $stop = mb_strlen($str, "UTF-8"); for($idx = 0) ;$idx< $stop; $idx++) { $char = mb_substr($str, $idx, 1, "UTF-8"); foreach (self::$TESTCHARS as $testchar) { if($char == $testchar) { $charcount++; break; } } } if($charcount>$charcountbest) ( $charcountbest=$charcount; $best=$charset; ) //echo $metin."
"; ) dönüş $en iyi; ) özel statik işlev __normalize($str) ( $len = strlen($str); $ret = ""; for($i = 0; $i< $len; $i++){ $c = ord($str[$i]); if ($c >128) ( if (($c > 247)) $ret .=$str[$i]; elseif ($c > 239) $bayt = 4; elseif ($c > 223) $bayt = 3; elseif ($ c > 191) $bytes = 2; else $ret .=$str[$i]; if (($i + $bytes) > $len) $ret .=$str[$i]; $ret2=$str [$i]; while ($bayt > 1) ( $i++; $b = ord($str[$i]); if ($b< 128 || $b >191) ($ret .=$ret2; $ret2=""; $i+=$bytes-1;$bytes=1; break;) else $ret2.=$str[$i]; $bayt--; ) ) ) $ret; ) özel statik işlev __iconv($string, $charset) ( return iconv ($charset, "UTF-8" , $string); ) )

PHP betiklerinizi sıraladıktan sonra mysql'e hangi kodlamayı geçtiğinizi ve almak istediğinizi söylemeyi unutmayın.

Örnek: karakter setini utf8 olarak ayarlamak

latin1 G/Ç oturumunda utf8 verilerini latin1 tablosuna geçirmek, bu kötü kuşları verir. Bunu her gün perakende mağazalarında görüyorum. İleri geri doğru görünebilir. Ama phpmyadmin gerçeği gösterecek. Hangi kodlamayı ilettiğinizi mysql'e söylemek işleyecektir mysql verileri senin için.

Mevcut şifreli mysql verilerinin nasıl kurtarılacağı, tartışılması gereken başka bir sorudur. :)