Php bagaimana untuk mengetahui pemetaan pengekodan. Menentukan pengekodan teks dalam PHP - gambaran keseluruhan penyelesaian sedia ada serta satu lagi basikal. Perkara yang dibawa oleh Google

Saya menghadapi masalah - pengesanan automatik halaman/teks/apa sahaja pengekodan. Tugas itu bukan baru, dan banyak basikal telah dicipta. Artikel itu mengandungi gambaran ringkas tentang perkara yang ditemui di Internet - ditambah dengan cadangan tentang perkara yang saya fikir adalah penyelesaian yang sesuai.

1. Mengapa tidak mb_detect_encoding()?

Pendek kata, ia tidak berfungsi.

Jom tonton:
// Di pintu masuk - teks Rusia dalam pengekodan CP1251 $string = iconv("UTF-8", "Windows-1251", "Dia mendekati Anna Pavlovna, mencium tangannya, mendedahkan kepala botaknya yang wangi dan bersinar kepadanya, dan dengan tenang duduk di sofa."); // Mari lihat apa yang md_detect_encoding() berikan kepada kita. Pertama $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 // Sekarang $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"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"), TRUE)); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"), TRUE)); // ISO-8859-5
Seperti yang anda lihat, outputnya adalah kekacauan yang lengkap. Apakah yang kita lakukan apabila tidak jelas mengapa fungsi berkelakuan seperti ini? Betul, mari kita Google. Saya mendapati jawapan yang hebat.

Untuk akhirnya menghilangkan semua harapan untuk menggunakan mb_detect_encoding(), anda perlu melihat ke dalam kod sumber sambungan mbstring. Jadi, singsingkan lengan baju anda dan mari pergi:
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // baris 2703 ret = mbfl_identify_encoding_name(&string, elist, size, strict); ...
Ctrl + klik:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:643 const char* mbfl_identify_encoding_name(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict) ( const mbfl_encoding *encoding; pengekodan = mbfl(_mengenal pasti_enkoding , tegas);...
Ctrl + klik:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * kenal pasti pengekodan */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict) ( ...
Saya tidak akan menyiarkan teks penuh kaedah, supaya tidak mengacaukan artikel dengan sumber yang tidak perlu. Mereka yang berminat akan lihat sendiri. Kami berminat dengan nombor baris 593, di mana kami sebenarnya menyemak sama ada aksara itu sepadan dengan pengekodan:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, filter); jika (penapis->bendera) ( buruk++; )
Berikut ialah penapis utama untuk Cyrillic bait tunggal:

Windows-1251 (komen asal dikekalkan)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* semua ini sangat hodoh sekarang! */ int statik mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *penapis) ( jika (c >= 0x80 && c< 0xff) filter->bendera = 0; penapis lain->

KOI8-R
// ext/mbstring/libmbfl/filters/mbfilter_koi8r.c:142 int statik mbfl_filt_ident_koi8r(int c, mbfl_identify_filter *penapis) ( jika (c >= 0x80 && c< 0xff) filter->bendera = 0; penapis lain->bendera = 1; /* bukan itu */ kembalikan c; )

ISO-8859-5 (semuanya menyeronokkan di sini)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *penapis) ( return c; )
Seperti yang anda lihat, ISO-8859-5 sentiasa mengembalikan BENAR (untuk mengembalikan FALSE, anda perlu menetapkan penapis->bendera = 1).

Apabila kami melihat penapis, semuanya jatuh ke tempatnya. Tidak ada cara untuk membezakan CP1251 daripada KOI8-R. Secara umum, ISO-8859-5, jika ia berada dalam senarai pengekodan, akan sentiasa dikesan sebagai betul.

Secara umum, gagal. Ini boleh difahami - secara umum, adalah mustahil untuk mengetahui pengekodan hanya dengan kod aksara, kerana kod ini bersilang dalam pengekodan yang berbeza.

2. Perkara yang dibawa oleh Google

Dan Google membangkitkan semua jenis kemelaratan. Saya tidak akan menyiarkan sumbernya di sini, lihat sendiri jika anda mahu (alih keluar ruang selepas http://, saya tidak tahu bagaimana untuk menunjukkan teks tanpa pautan):

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

3. Cari mengikut hab

1) sekali lagi kod aksara: habrahabr.ru/blogs/php/27378/#comment_710532

2) pada pendapat saya, penyelesaian yang sangat menarik: habrahabr.ru/blogs/php/27378/#comment_1399654
Kebaikan dan keburukan dalam ulasan pada pautan. Secara peribadi, saya berpendapat bahawa penyelesaian ini berlebihan hanya untuk pengesanan pengekodan - ternyata ia terlalu berkuasa. Mentakrifkan pengekodan di dalamnya adalah kesan sampingan).

4. Sebenarnya, keputusan saya

Idea itu timbul semasa melihat pautan kedua dari bahagian sebelumnya. Ideanya adalah seperti berikut: kami mengambil teks Rusia yang besar, mengukur frekuensi huruf yang berbeza, dan menggunakan frekuensi ini untuk mengesan pengekodan. Memandang ke hadapan, saya akan segera mengatakan bahawa akan ada masalah dengan huruf besar dan kecil. Oleh itu, saya menyiarkan contoh frekuensi huruf (mari kita panggil ia "spektrum"), kedua-dua sensitif huruf dan tidak sensitif huruf (dalam kes kedua, saya menambah yang lebih besar pada huruf kecil dengan kekerapan yang sama, dan mengalih keluar semua yang lebih besar). Dalam "spektra" ini semua huruf dengan frekuensi kurang daripada 0.001 dan ruang dipotong. Inilah yang saya dapat selepas memproses "Perang dan Keamanan":

"spektrum" sensitif huruf besar-besaran:
tatasusunan ("o" => 0.095249209893009, "e" => 0.06836817536026, "a" => 0.067481298384992, "i" => 0.055995027400041, "n" => 2, "n" => 2, "n" => 2 002252892226507, "N " => 0.0021318391371162, "P" => 0.0018574762967903, "f" => 0.0015961610948418, "B" => 0.0014044332975731, "O0" => 8, "O0" => 8 .0012623590130186, "K" => 0.0011804488387602, "M" => 0.001061932790165,)

Kes tidak sensitif:
tatasusunan ("O" => 0.095249209893009, "o" => 0.095249209893009, "E" => 0.06836817536026, "e" => 0.06836817536026, "A" => 8.06, "A" > 8.026. 67481298384992, "Saya" => 0.055995027400041 , "i" => 0.055995027400041, .... "C" => 0.0029893589260344, "c" => 0.0029893589260344, "c" => 0.0024649160344, "c" => 0.0029893589260344, "c" => 0.002464916350140 => 6,002464916350140 E" => 0.002252892226507, "e " => 0.002252892226507, "F" => 0.0015961610948418, "f" => 0.0015961610948418,)

Spektrum dalam pengekodan yang berbeza (kunci tatasusunan ialah kod aksara yang sepadan dalam pengekodan yang sesuai):

Selanjutnya. Kami mengambil teks pengekodan yang tidak diketahui, untuk setiap pengekodan yang disemak, kami mencari kekerapan aksara semasa dan menambahkannya pada "penilaian" pengekodan ini. Pengekodan dengan rating tertinggi kemungkinan besar adalah pengekodan teks.

$encodings = array("cp1251" => memerlukan "specter_cp1251.php", "koi8r" => memerlukan "specter_koi8r.php", "iso88595" => memerlukan "specter_iso88595.php"); $enc_rates = array(); untuk ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ($enc_rates[$encoding] += $char_specter)]; ) ) var_dump($enc_rates);
Jangan cuba jalankan sendiri kod ini - ia tidak akan berfungsi. Anda boleh mempertimbangkan pseudokod ini - Saya telah meninggalkan butiran supaya tidak mengacaukan artikel. $char_specter ialah tatasusunan yang dirujuk dalam pastebin.

keputusan
Baris jadual ialah pengekodan teks, lajur ialah kandungan tatasusunan $enc_rates.

1) $str = "Teks bahasa Rusia";
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

Semuanya baik-baik sahaja. Pengekodan sebenar sudah mempunyai penarafan 4 kali lebih tinggi daripada yang lain - ini adalah untuk teks yang begitu singkat. Untuk teks yang lebih panjang nisbahnya akan lebih kurang sama.


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

Aduh! Kekacauan yang lengkap. Itu kerana huruf besar dalam CP1251 biasanya sepadan dengan huruf kecil dalam KOI8-R. Dan huruf kecil, sebaliknya, digunakan lebih kerap daripada yang besar. Jadi kami mentakrifkan rentetan topi dalam CP1251 sebagai KOI8-R.
Mari cuba lakukannya secara tidak sensitif huruf ("spektra" tidak sensitif huruf)

1) $str = "Teks bahasa Rusia";
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 CAPS RUSSIAN TEKS";
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

Seperti yang anda boleh lihat, pengekodan yang betul secara konsisten mendahului kedua-duanya dengan "spektrum" sensitif huruf besar-besaran (jika baris mengandungi sejumlah kecil huruf besar) dan dengan huruf kecil yang tidak sensitif. Dalam kes kedua, dengan yang tidak peka huruf besar-besaran, peneraju tidak begitu yakin, sudah tentu, tetapi agak stabil walaupun pada garisan kecil. Anda juga boleh bermain-main dengan berat huruf - jadikannya tidak linear berkenaan dengan kekerapan, contohnya.

5. Kesimpulan

Topik ini tidak meliputi kerja dengan UTF-8 - tidak ada perbezaan asas di sini, kecuali bahawa mendapatkan kod aksara dan membahagi rentetan kepada aksara akan menjadi agak lebih panjang/lebih kompleks.
Idea ini boleh diperluaskan bukan sahaja kepada pengekodan Cyrillic, sudah tentu - persoalannya hanya dalam "spektrum" bahasa/pengekodan yang sepadan.

P.S. Jika ia benar-benar perlu/menarik, maka saya akan menyiarkan bahagian kedua perpustakaan yang berfungsi sepenuhnya di GitHub. Walaupun saya percaya bahawa data dalam siaran itu cukup untuk menulis perpustakaan sedemikian dengan cepat untuk memenuhi keperluan anda sendiri - "spektrum" untuk bahasa Rusia telah dibentangkan, ia boleh dipindahkan dengan mudah ke semua pengekodan yang diperlukan.

Saya menghadapi masalah - pengesanan automatik halaman/teks/apa sahaja pengekodan. Tugas itu bukan baru, dan banyak basikal telah dicipta. Artikel itu mengandungi gambaran ringkas tentang perkara yang ditemui di Internet - ditambah dengan cadangan tentang perkara yang saya fikir adalah penyelesaian yang sesuai.

1. Mengapa tidak mb_detect_encoding()?

Pendek kata, ia tidak berfungsi.

Jom tonton:
// Di pintu masuk - teks Rusia dalam pengekodan CP1251 $string = iconv("UTF-8", "Windows-1251", "Dia mendekati Anna Pavlovna, mencium tangannya, mendedahkan kepala botaknya yang wangi dan bersinar kepadanya, dan dengan tenang duduk di sofa."); // Mari lihat apa yang md_detect_encoding() berikan kepada kita. Pertama $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 // Sekarang $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"), TRUE)); // FALSE var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"), TRUE)); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"), TRUE)); // ISO-8859-5
Seperti yang anda lihat, outputnya adalah kekacauan yang lengkap. Apakah yang kita lakukan apabila tidak jelas mengapa fungsi berkelakuan seperti ini? Betul, mari kita Google. Saya mendapati jawapan yang hebat.

Untuk akhirnya menghilangkan semua harapan untuk menggunakan mb_detect_encoding(), anda perlu melihat ke dalam kod sumber sambungan mbstring. Jadi, singsingkan lengan baju anda dan mari pergi:
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // baris 2703 ret = mbfl_identify_encoding_name(&string, elist, size, strict); ...
Ctrl + klik:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:643 const char* mbfl_identify_encoding_name(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict) ( const mbfl_encoding *encoding; pengekodan = mbfl(_mengenal pasti_enkoding , tegas);...
Ctrl + klik:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * kenal pasti pengekodan */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict) ( ...
Saya tidak akan menyiarkan teks penuh kaedah, supaya tidak mengacaukan artikel dengan sumber yang tidak perlu. Mereka yang berminat akan lihat sendiri. Kami berminat dengan nombor baris 593, di mana kami sebenarnya menyemak sama ada aksara itu sepadan dengan pengekodan:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, filter); jika (penapis->bendera) ( buruk++; )
Berikut ialah penapis utama untuk Cyrillic bait tunggal:

Windows-1251 (komen asal dikekalkan)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* semua ini sangat hodoh sekarang! */ int statik mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *penapis) ( jika (c >= 0x80 && c< 0xff) filter->bendera = 0; penapis lain->

KOI8-R
// ext/mbstring/libmbfl/filters/mbfilter_koi8r.c:142 int statik mbfl_filt_ident_koi8r(int c, mbfl_identify_filter *penapis) ( jika (c >= 0x80 && c< 0xff) filter->bendera = 0; penapis lain->bendera = 1; /* bukan itu */ kembalikan c; )

ISO-8859-5 (semuanya menyeronokkan di sini)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *penapis) ( return c; )
Seperti yang anda lihat, ISO-8859-5 sentiasa mengembalikan BENAR (untuk mengembalikan FALSE, anda perlu menetapkan penapis->bendera = 1).

Apabila kami melihat penapis, semuanya jatuh ke tempatnya. Tidak ada cara untuk membezakan CP1251 daripada KOI8-R. Secara umum, ISO-8859-5, jika ia berada dalam senarai pengekodan, akan sentiasa dikesan sebagai betul.

Secara umum, gagal. Ini boleh difahami - secara umum, adalah mustahil untuk mengetahui pengekodan hanya dengan kod aksara, kerana kod ini bersilang dalam pengekodan yang berbeza.

2. Perkara yang dibawa oleh Google

Dan Google membangkitkan semua jenis kemelaratan. Saya tidak akan menyiarkan sumbernya di sini, lihat sendiri jika anda mahu (alih keluar ruang selepas http://, saya tidak tahu bagaimana untuk menunjukkan teks tanpa pautan):

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

3. Cari mengikut hab

1) sekali lagi kod aksara:

2) pada pendapat saya, penyelesaian yang sangat menarik:
Kebaikan dan keburukan dalam ulasan pada pautan. Secara peribadi, saya berpendapat bahawa penyelesaian ini berlebihan hanya untuk pengesanan pengekodan - ternyata ia terlalu berkuasa. Mentakrifkan pengekodan di dalamnya adalah kesan sampingan).

4. Sebenarnya, keputusan saya

Idea itu timbul semasa melihat pautan kedua dari bahagian sebelumnya. Ideanya adalah seperti berikut: kami mengambil teks Rusia yang besar, mengukur frekuensi huruf yang berbeza, dan menggunakan frekuensi ini untuk mengesan pengekodan. Memandang ke hadapan, saya akan segera mengatakan bahawa akan ada masalah dengan huruf besar dan kecil. Oleh itu, saya menyiarkan contoh frekuensi huruf (mari kita panggil ia "spektrum"), kedua-dua sensitif huruf dan tidak sensitif huruf (dalam kes kedua, saya menambah yang lebih besar pada huruf kecil dengan kekerapan yang sama, dan mengalih keluar semua yang lebih besar). Dalam "spektra" ini semua huruf dengan frekuensi kurang daripada 0.001 dan ruang dipotong. Inilah yang saya dapat selepas memproses "Perang dan Keamanan":

"spektrum" sensitif huruf besar-besaran:
tatasusunan ("o" => 0.095249209893009, "e" => 0.06836817536026, "a" => 0.067481298384992, "i" => 0.055995027400041, "n" => 2, "n" => 2, "n" => 2 002252892226507, "N " => 0.0021318391371162, "P" => 0.0018574762967903, "f" => 0.0015961610948418, "B" => 0.0014044332975731, "O0" => 8, "O0" => 8 .0012623590130186, "K" => 0.0011804488387602, "M" => 0.001061932790165,)

Kes tidak sensitif:
tatasusunan ("O" => 0.095249209893009, "o" => 0.095249209893009, "E" => 0.06836817536026, "e" => 0.06836817536026, "A" => 8.06, "A" > 8.026. 67481298384992, "Saya" => 0.055995027400041 , "i" => 0.055995027400041, .... "C" => 0.0029893589260344, "c" => 0.0029893589260344, "c" => 0.0024649160344, "c" => 0.0029893589260344, "c" => 0.002464916350140 => 6,002464916350140 E" => 0.002252892226507, "e " => 0.002252892226507, "F" => 0.0015961610948418, "f" => 0.0015961610948418,)

Spektrum dalam pengekodan yang berbeza (kunci tatasusunan ialah kod aksara yang sepadan dalam pengekodan yang sesuai):

Selanjutnya. Kami mengambil teks pengekodan yang tidak diketahui, untuk setiap pengekodan yang disemak, kami mencari kekerapan aksara semasa dan menambahkannya pada "penilaian" pengekodan ini. Pengekodan dengan rating tertinggi kemungkinan besar adalah pengekodan teks.

$encodings = array("cp1251" => memerlukan "specter_cp1251.php", "koi8r" => memerlukan "specter_koi8r.php", "iso88595" => memerlukan "specter_iso88595.php"); $enc_rates = array(); untuk ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ($enc_rates[$encoding] += $char_specter)]; ) ) var_dump($enc_rates);
Jangan cuba jalankan sendiri kod ini - ia tidak akan berfungsi. Anda boleh mempertimbangkan pseudokod ini - Saya telah meninggalkan butiran supaya tidak mengacaukan artikel. $char_specter ialah tatasusunan yang dirujuk dalam pastebin.

keputusan
Baris jadual ialah pengekodan teks, lajur ialah kandungan tatasusunan $enc_rates.

1) $str = "Teks bahasa Rusia";
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

Semuanya baik-baik sahaja. Pengekodan sebenar sudah mempunyai penarafan 4 kali lebih tinggi daripada yang lain - ini adalah untuk teks yang begitu singkat. Untuk teks yang lebih panjang nisbahnya akan lebih kurang sama.


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

Aduh! Kekacauan yang lengkap. Itu kerana huruf besar dalam CP1251 biasanya sepadan dengan huruf kecil dalam KOI8-R. Dan huruf kecil, sebaliknya, digunakan lebih kerap daripada yang besar. Jadi kami mentakrifkan rentetan topi dalam CP1251 sebagai KOI8-R.
Mari cuba lakukannya secara tidak sensitif huruf ("spektra" tidak sensitif huruf)

1) $str = "Teks bahasa Rusia";
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 CAPS RUSSIAN TEKS";
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

Seperti yang anda boleh lihat, pengekodan yang betul secara konsisten mendahului kedua-duanya dengan "spektrum" sensitif huruf besar-besaran (jika baris mengandungi sejumlah kecil huruf besar) dan dengan huruf kecil yang tidak sensitif. Dalam kes kedua, dengan yang tidak peka huruf besar-besaran, peneraju tidak begitu yakin, sudah tentu, tetapi agak stabil walaupun pada garisan kecil. Anda juga boleh bermain-main dengan berat huruf - jadikannya tidak linear berkenaan dengan kekerapan, contohnya.

5. Kesimpulan

Topik ini tidak meliputi kerja dengan UTF-8 - tidak ada perbezaan asas di sini, kecuali bahawa mendapatkan kod aksara dan membahagi rentetan kepada aksara akan menjadi agak lebih panjang/lebih kompleks.
Idea ini boleh diperluaskan bukan sahaja kepada pengekodan Cyrillic, sudah tentu - persoalannya hanya dalam "spektrum" bahasa/pengekodan yang sepadan.

P.S. Jika ia benar-benar perlu/menarik, maka saya akan menyiarkan bahagian kedua perpustakaan yang berfungsi sepenuhnya di GitHub. Walaupun saya percaya bahawa data dalam siaran itu cukup untuk menulis perpustakaan sedemikian dengan cepat untuk memenuhi keperluan anda sendiri - "spektrum" untuk bahasa Rusia telah dibentangkan, ia boleh dipindahkan dengan mudah ke semua pengekodan yang diperlukan.

Idea - Loteri

Saya tidak mendapat idea untuk mendapatkan pengekodan, tetapi malangnya, saya tidak dapat memberitahu anda pengarang sekarang, kerana ia adalah kira-kira 4 tahun yang lalu dan dari mana saya mendapat maklumat ini telah lama dilupakan. Penulis mencadangkan definisi dan menunjukkan contoh untuk 1-2 pengekodan dalam Python. Kesederhanaan penyelesaiannya tidak mengetepikan saya, dan saya mengembangkannya untuk hasil yang diinginkan.
Intipati idea terletak pada jadual kod pengekodan itu sendiri. Seperti yang anda ketahui, sebarang pengekodan mengandungi jadual kodnya sendiri dan setiap aksara pengekodan diberikan nilai tertentu. Saya tidak akan menunjukkan jadual pengekodan di sini; kini ia agak mudah dicari di Internet.
Prinsip pelaksanaan adalah seperti berikut:
  1. Pembolehubah tatasusunan dicipta untuk menyimpan hasil "analisis" teks yang diperiksa. Setiap elemen tatasusunan akan mengandungi hasil untuk pengekodan tertentu.
  2. Teks yang diterima sebagai input kepada fungsi diulang secara simbolik.
  3. Ordinal (maksud aksara itu) diambil daripada setiap aksara dan dibandingkan dengan julat pengekodan.
  4. Jika nilai jatuh pada aksara huruf besar (kapital), nilai 1 ditambahkan pada elemen tatasusunan yang menyimpan hasil pengekodan ini.
  5. Jika nilai jatuh pada aksara huruf kecil (kecil), nilai 3 ditambahkan pada elemen tatasusunan yang menyimpan hasil pengekodan ini.
  6. Pengekodan itu, atau lebih tepat lagi, elemen tatasusunan yang menyimpan hasil pengekodannya, yang memperoleh mata terbanyak, kemungkinan besar adalah pengekodan asal.
Algoritma ini sah untuk pengekodan bait tunggal seperti KOI-8, CP1251 (windows-1251) dan lain-lain. Walau bagaimanapun, untuk pengekodan dua bait (UTF-8 dalam kes saya), pendekatan ini akan menghasilkan keputusan yang salah. Sebagai permulaan, saya cuba menyelesaikan isu ini dengan menambah 5 untuk aksara besar dan 7 untuk aksara kecil. Hasilnya menjadi lebih baik, tetapi ralat pengecaman masih wujud. Selepas beberapa percubaan, saya membuat kesimpulan bahawa untuk menentukan UTF dengan betul, untuk aksara besar, 10 harus ditambah pada hasilnya, untuk aksara kecil, 14, iaitu, 2 kali lebih banyak daripada tekaan awal saya. Walau bagaimanapun, untuk pemahaman visual yang lebih baik tentang kod, saya meninggalkan 5 dan 7 untuk aksara UTF, masing-masing, dan semasa ujian saya meningkatkan nilai ini sebanyak 2 dan menambahkannya pada hasilnya.
Itulah pada dasarnya keseluruhan algoritma. Dan tanpa sebarang kerumitan yang tidak perlu.
Kebanyakan masa yang saya habiskan untuk melaksanakan fungsi ini, sudah tentu, mencari jadual kod dan susunan julat yang betul. Bukan sahaja agak sukar untuk mencari jadual kod semasa pada masa saya mula-mula menulis fungsi ini, tetapi julat aksara di dalamnya melompat-lompat secara rawak. Walau bagaimanapun, saya kemudiannya menyelesaikan pengekodan terkini (dan sehingga hari ini): UTF-8, CP1251, KOI8-R, IBM866, ISO-8859-5 dan MAC. Jika pengekodan ini tidak mencukupi untuk anda, anda boleh menambah kod berdasarkan algoritma ini.

Dari perkataan kepada amalan

Sebenarnya, keseluruhan kod fungsi dalam Python kelihatan seperti ini:

Pengekodan = ( "UTF-8": "utf-8", "CP1251": "windows-1251", "KOI8-R": "koi8-r", "IBM866": "ibm866", "ISO-8859- 5": "iso-8859-5", "MAC": "mac", ) """ Menentukan pengekodan teks """ def get_codepage(str = Tiada): huruf besar = 1 huruf kecil = 3 utfupper = 5 utflower = 7 codepages = () untuk enc dalam encodings.keys(): codepages = 0 jika str bukan Tiada dan len(str) > 0: last_simb = 0 untuk simb dalam str: simb_ord = ord(simb) """aksara bukan Rusia " "" jika simb_ord< 128 or simb_ord >256: teruskan """UTF-8""" jika last_simb == 208 dan (143< 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 = codepages idx = item return idx
Contoh panggilan fungsi

Pengekodan cetakan

Bagaimana dengan PHP?

Menulis semula fungsi siap dari Python ke PHP tidaklah sukar. Dari segi penampilan, ia boleh dikatakan tidak berbeza daripada induknya dalam Python:

/** * Tentukan pengekodan teks * @param String $text Text * @return String Text encoding */ function get_codepage($text = "") ( if (!empty ($text)) ($utflower = 7; $utfupper = 5; $huruf kecil = 3; $huruf besar = 1; $last_simb = 0; $charsets = array("UTF-8" => 0, "CP1251" => 0, "KOI8-R" => 0, "IBM866 " => 0, "ISO-8859-5" => 0, "MAC" => 0,); untuk ($a = 0; $a< strlen($text); $a++) { $char = ord($text[$a]); // non-russian characters if ($char<128 || $char>256) teruskan; // UTF-8 jika (($last_simb==208) && (($char>143 && $char<176) || $char==129)) $charsets["UTF-8"] += ($utfupper * 2); if ((($last_simb==208) && (($char>175 && $char<192) || $char==145)) || ($last_simb==209 && $char>127 && $char<144)) $charsets["UTF-8"] += ($utflower * 2); // CP1251 if (($char>223 && $char<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 && $char<256) || $char==179) $charsets["KOI8-R"] += $uppercase; // IBM866 if (($char>159 && $char<176) || ($char>223 && $char<241)) $charsets["IBM866"] += $lowercase; if (($char>127 && $char<160) || $char==241) $charsets["IBM866"] += $uppercase; // ISO-8859-5 if (($char>207 && $char<240) || $char==161) $charsets["ISO-8859-5"] += $lowercase; if (($char>175 && $char<208) || $char==241) $charsets["ISO-8859-5"] += $uppercase; // MAC if ($char>221 && $char<255) $charsets["MAC"] += $lowercase; if ($char>127 && $char<160) $charsets["MAC"] += $uppercase; $last_simb = $char; } arsort($charsets); return key($charsets); } }
Contoh panggilan fungsi

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

LikBez, atau Jangan ganggu kerja mesin

Anda tidak sepatutnya cuba ranap menguji fungsi ini. Jelas daripada algoritma bahawa semakin sedikit teks yang diterima sebagai input, semakin besar kemungkinan fungsi tersebut akan mengecam pengekodan secara tidak betul. Sebaliknya, memberi makan jumlah Leo Tolstoy juga tidak masuk akal: kaedah ini mengatasi dengan baik dengan ayat kecil 100-200 aksara. Dan walaupun dalam contoh panggilan ke input saya menghantar keseluruhan kandungan fail tertentu "test.txt", yang sepatutnya mengandungi teks yang pengekodannya perlu ditentukan, sebahagian kecil teks boleh (dan harus) dihantar ke input fungsi.
Saya menganggap penyimpangan dengan campuran huruf besar dan huruf kecil secara amnya tidak sesuai dalam kes ini, kerana kaedah ini ditulis untuk tugas biasa yang dijalankan dengan lebih kurang celik bahasa Rusia. Dan eksperimen sedemikian paling kerap mengingatkan saya tentang jenaka:

Sebuah kilang pemprosesan kayu Rusia memperoleh unit Jepun. Pekerja Rusia berkumpul di sekelilingnya dan mari kita fikirkan cara dia bekerja. Seorang mengambil papan itu dan memasukkannya ke dalamnya. Unit:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz... At the exit is a finished stool. Lelaki: Wah!!! Unit yang dipamerkan: baik, apa yang anda fikirkan? Seorang lagi mengambil kayu balak yang belum ditebang dan memasukkannya ke dalam unit. Unit: Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzazzzzzzzing. Lelaki: Wah!!! Unit yang dipamerkan: baik, apa yang anda fikirkan? Lelaki ketiga tidak tahan, menarik rel dari suatu tempat dan melekatkannya ke dalam unit. Unit: drrrrrrr-tyh-tyh-tyh... Ia mula berasap dan paparan berbunyi: Wow!!! Lelaki: Nah, apa yang anda fikirkan !!!
Jadi untuk ujian berpintal sedemikian, anda kemungkinan besar memerlukan algoritma berpintal, yang mana fungsi ini tidak. Dan dari amalan saya akan mengatakan bahawa selama saya menggunakan selama 4 tahun, kaedah ini tidak pernah mengecewakan saya dan sentiasa memberikan hasil yang betul.
Saya harap artikel saya akan berguna kepada seseorang.
Terima kasih kerana memberi perhatian.

Apabila menggunakan semua atau sebahagian daripada kandungan, jangan lupa untuk memberikan pautan kepada sumber, iaitu, ke blog saya.

Masalah telah timbul: bagaimana untuk menentukan pengekodan rentetan teks dengan pantas berbanding UTF-8. Semakin kerap kita perlu bekerja dengan rentetan dalam pengekodan UNICODE.

Di bawah ialah fungsi untuk menyemak sama ada pengekodan UNICODE (UTF-8) perlu ditukar kepada pengekodan WINDOWS (win-1251)

Fungsi ini memberikan jawapan yang agak tepat, walaupun ia tidak berdasarkan penukaran aksara demi kod.

fungsi detect_my_utf($s)( $s=urlencode($s); // dalam beberapa kes - operasi yang tidak perlu (komen keluar) $res="0"; $j=strlen($s); $s2=strtoupper($ s); $s2=str_replace("%D0","",$s2); $s2=str_replace("%D1","",$s2); $k=strlen($s2); $m=1 ; jika ($k>0)( $m=$j/$k; jika (($m>1.2)&&($m

Penerangan ringkas tentang fungsi detect_my_utf():

  • tukar (rentetan kepada format khas)
  • hitung panjang rentetan yang masuk
  • huruf besar semua huruf rentetan
  • alih keluar kod tertentu %D0 dan %D1
  • hitung panjang baris baharu itu
  • kita mendapat nisbah baris lama kepada yang baru

Jika nisbah ini ialah 1 atau hampir dengannya, maka disyaki rentetan masuk tidak dikodkan dalam UNICODE. Jika nisbah ini berada dalam julat dari 1.2 hingga 2.2, maka anda boleh mengekod semula rentetan dengan selamat ke dalam pengekodan WINDOWS win-1251.

Output fungsi ialah 0 atau 1, masing-masing, bukan UNICODE atau UNICODE.

Contoh pelaksanaan fungsi:

Talian masuk: РїР?С?Р?Р?Рє С?Р?Р·Р?Р°Р?РёС? Bahasa Melayu siap imej Rentetan ditukar: %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 Hasil fungsi: 1 Dikodkan frasa: susunan penciptaan animasi dalam imageready

Rentetan masuk: R?S?R?R?R?S

Rentetan masuk: РїС?Р?Р?С?Р°Р?Р?Р° С+їРур?

Rentetan input: panduan lukisan Rentetan ditukar: %EF%EE%F1%EE%E1%E8%E5 %EF%EE %F0%E8%F1%EE%E2%E0%ED%E8%FE Hasil fungsi: 0 Frasa yang dikodkan : panduan lukisan Algoritma ini mengatasi dengan baik pelbagai rentetan masuk sebagai sebahagian daripada perkhidmatan statistik penukaran enjin carian.

Bahan-bahan menarik di laman web:

  • Artikel tentang minat enjin carian tapak. Mungkin sesetengah bahan sudah lapuk selepas 10 tahun, tetapi beberapa perkara patut diberi perhatian.

  • Pandangan anda tentang masalah pertukaran hiperpautan antara tapak penderma dan tapak penerima.

  • Satu lagi life hack. Kami mengalahkan pemain yang tidak jujur ​​dalam permainan "Balda". Pangkalan data perkataan yang besar yang boleh dikembangkan dengan mudah.

Saya membaca banyak teks daripada suapan RSS yang berbeza dan memasukkannya ke dalam pangkalan data saya.

Sudah tentu, terdapat beberapa pengekodan aksara berbeza yang digunakan dalam paip, mis. UTF-8 dan ISO-8859-1.

Malangnya, kadangkala masalah timbul dengan pengekodan teks. Contoh:

1) "ß" dalam "Fußball" sepatutnya kelihatan seperti ini dalam pangkalan data saya: "Ÿ". Jika ia adalah "Ÿ", ia dipaparkan dengan betul.

2) Kadangkala "ß" dalam "Fußball" kelihatan seperti ini dalam pangkalan data saya: "ß". Kemudian ia dipaparkan secara tidak betul, sudah tentu.

3) Dalam kes lain, "ß" disimpan sebagai "ß" - oleh itu tanpa sebarang perubahan. Kemudian ia juga dipaparkan secara tidak betul.

Apakah yang boleh saya lakukan untuk mengelakkan kes 2 dan 3?

Bagaimanakah saya boleh menjadikan semua pengekodan yang sama, sebaik-baiknya UTF-8? Bilakah saya harus menggunakan utf8_encode(), bilakah saya harus menggunakan utf8_decode() (jelas apakah kesannya, tetapi bilakah saya harus menggunakan fungsi?), dan bilakah saya harus melakukan apa-apa dengan input?

Bolehkah anda membantu saya dan memberitahu saya cara membuat semua pengekodan yang sama? Mungkin dengan fungsi mb-detect-encoding()? Bolehkah saya menulis fungsi untuk ini? Jadi masalah saya ialah: 1) Bagaimana untuk mengetahui pengekodan yang digunakan dalam teks 2) Bagaimana untuk menukarnya kepada UTF-8 - tanpa mengira pengekodan lama

EDIT: Adakah ciri ini akan berfungsi?

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

Saya mengujinya tetapi ia tidak berfungsi. Apa masalah dia?

24 jawapan

Jika anda menggunakan utf8_encode() pada rentetan UTF8 yang sedia ada, ia akan mengembalikan output UTF8 yang kacau.

Saya mencipta fungsi yang menyelesaikan semua masalah ini. Ia dipanggil Pengekodan::toUTF8().

Anda tidak perlu tahu apakah pengekodan rentetan anda. Ini mungkin Latin1 (iso 8859-1), Windows-1252 atau UTF8, atau rentetan mungkin mengandunginya. Pengekodan::toUTF8() menukarkan semuanya kepada UTF8.

Saya melakukan ini kerana perkhidmatan itu memberi saya aliran data, semuanya kacau, mencampurkan UTF8 dan Latin1 dalam satu baris.

penggunaan:

Require_once("Pengekodan.php"); gunakan \ForceUTF8\Encoding; // Ia diberi ruang nama sekarang. $utf8_string = Pengekodan::toUTF8($utf8_or_latin1_or_mixed_string); $latin1_string = Pengekodan::toLatin1($utf8_or_latin1_or_mixed_string);

Saya telah memasukkan fungsi lain, Pengekodan::fixUFT8(), yang akan membetulkan setiap rentetan UTF8 yang kelihatan kacau.

penggunaan:

Require_once("Pengekodan.php"); gunakan \ForceUTF8\Encoding; // Ia diberi ruang nama sekarang. $utf8_string = Pengekodan::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("Fédération Camerounaise de Football");

Fédération Camerounaise de Football Fédération Camerounaise de Football Fédération Camerounaise de Football Fédération Camerounaise de Football

Kemas kini: Saya menukar fungsi (forceUTF8) kepada keluarga fungsi statik dalam kelas Pengekodan. Fungsi baharu - Pengekodan::toUTF8().

Mula-mula anda perlu menentukan pengekodan yang digunakan. Memandangkan anda sedang menghuraikan suapan RSS (mungkin melalui HTTP), anda harus membaca pengekodan daripada parameter charset medan Jenis Kandungan pengepala HTTP. Jika tiada, baca pengekodan daripada atribut pengekodan arahan pemprosesan. Jika ini juga tiada, gunakan UTF-8 seperti yang ditakrifkan dalam spesifikasi.

Ubah Inilah yang mungkin saya lakukan:

Mengesan pengekodan adalah sukar.

mb_detect_encoding berfungsi dengan meneka berdasarkan berbilang calon yang anda luluskan. Dalam sesetengah pengekodan, jujukan bait tertentu adalah tidak sah, jadi ia boleh membezakan antara calon yang berbeza. Malangnya, terdapat banyak pengekodan di mana bait yang sama adalah sah (tetapi berbeza). Dalam kes ini, adalah mustahil untuk menentukan pengekodan; Anda boleh melaksanakan logik anda sendiri untuk membuat tekaan dalam kes ini. Sebagai contoh, data yang datang dari tapak Jepun kemungkinan besar dalam pengekodan Jepun.

Walaupun anda hanya berurusan dengan bahasa Eropah Barat, mari lihat tiga pengekodan utama: utf-8, iso-8859-1 dan cp-1252. Oleh kerana ini adalah nilai lalai untuk banyak platform, ia juga mungkin akan dilaporkan secara tersilap. Sebagai contoh. jika orang menggunakan pengekodan yang berbeza, mereka mungkin akan terbuka mengenainya, kerana jika tidak perisian mereka akan rosak dengan kerap. Jadi strategi yang baik adalah mempercayai pembekal melainkan pengekodan diisytiharkan sebagai salah satu daripada tiga ini. Anda masih harus menggandakan bahawa ia sebenarnya sah menggunakan mb_check_encoding (perhatikan bahawa sah tidak sama seperti - input yang sama boleh sah untuk banyak pengekodan). Jika ia adalah salah satu daripadanya, anda boleh menggunakan mb_detect_encoding untuk membezakan antara mereka. Nasib baik, ini agak deterministik; Anda hanya perlu menggunakan urutan pengesanan yang betul, iaitu UTF-8,ISO-8859-1,WINDOWS-1252.

Sebaik sahaja anda menemui pengekodan, anda perlu menukarnya kepada perwakilan dalaman (utf-8 ialah satu-satunya pilihan yang munasabah). Fungsi utf8_encode menukarkan iso-8859-1 kepada utf-8 supaya ia hanya boleh digunakan untuk jenis input tertentu itu. Untuk pengekodan lain, gunakan mb_convert_encoding.

Helaian cheat ini menyenaraikan beberapa kaveat biasa yang berkaitan dengan pengendalian UTF-8 dalam PHP: http://developer.loftdigital.com/blog/php-utf-8-cheatsheet

Fungsi ini, yang mengesan aksara multibait dalam rentetan, mungkin juga berguna ():

Fungsi detectUTF8($string) ( return preg_match("%(?: [\xC2-\xDF][\x80-\xBF] # 2-bait tidak terlalu panjang |\xE0[\xA0-\xBF][\x80- \xBF] # tidak termasuk overlong |[\xE1-\xEC\xEE\xEF][\x80-\xBF](2) # lurus 3-bait |\xED[\x80-\x9F][\x80-\xBF] # tidak termasuk pengganti |\xF0[\x90-\xBF][\x80-\xBF](2) # pesawat 1-3 |[\xF1-\xF3][\x80-\xBF](3) # pesawat 4- 15 |\xF4[\x80-\x8F][\x80-\xBF](2) # satah 16)+%xs", $string); )

Sedikit makluman, anda berkata bahawa "ß" sepatutnya muncul sebagai "Ÿ" dalam pangkalan data anda.

Ini mungkin disebabkan oleh fakta bahawa anda menggunakan pangkalan data dengan pengekodan aksara latin1 atau mungkin sambungan php-mysql tidak dikonfigurasikan dengan betul, php menganggap bahawa mysql anda dikonfigurasikan untuk menggunakan utf-8 jadi ia menghantar data sebagai utf8 tetapi anda mysql percaya php menghantar data yang dikodkan sebagai iso-8859-1, jadi ia mungkin cuba mengekod data anda yang dihantar sebagai utf-8 sekali lagi, menyebabkan masalah seperti ini.

Lihat ini, ia mungkin membantu anda: http://php.net/manual/en/function.mysql-set-charset.php

Anda perlu menyemak pengekodan pada input kerana respons mungkin dikodkan dengan pengekodan yang berbeza.
Saya memaksa semua kandungan dihantar dalam UTF-8 dengan melakukan pengesanan dan terjemahan menggunakan fungsi berikut:

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); jika (!$encoding) diteruskan; if (strcasecmp($encoding, "UTF-8") != 0) ($encoding = iconv($encoding, " UTF-8", $var[ $key ]); jika ($encoding === false) diteruskan; $var[ $key ] = $encoding; ) ) ) )

Prosedur ini akan menukar semua pembolehubah PHP yang datang dari hos jauh kepada UTF-8.
Atau abaikan nilai jika pengekodan tidak dapat dikesan atau ditukar.
Anda boleh menyesuaikannya mengikut keperluan anda.
Panggil sahaja sebelum menggunakan pembolehubah.

Pengekodan anda kelihatan seperti anda dikodkan dalam UTF-8 dua kali; iaitu, daripada beberapa pengekodan lain, kepada UTF-8 dan sekali lagi kepada UTF-8. Seolah-olah anda telah menukar iso-8859-1 daripada iso-8859-1 kepada utf-8 dan dirawat dengan baris baharu sebagai iso-8859-1 untuk penukaran lain kepada UTF-8.

Berikut ialah beberapa pseudokod untuk perkara yang anda lakukan:

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

Anda mesti mencuba:

  • mengesan pengekodan menggunakan mb_detect_encoding() atau apa sahaja yang anda suka gunakan
  • jika UTF-8, tukar kepada iso-8859-1 dan ulangi langkah 1
  • akhirnya tukar semula kepada UTF-8

Diandaikan bahawa dalam penukaran "purata" anda menggunakan iso-8859-1. Jika anda menggunakan windows-1252, kemudian tukar kepada windows-1252 (latin1). Pengekodan asal sumber tidak penting; yang anda gunakan dalam penukaran kedua yang salah.

Ini adalah tekaan saya tentang apa yang berlaku; anda boleh melakukan lebih sedikit untuk mendapatkan empat bait dan bukannya satu bait ASCII yang dilanjutkan.

Bahasa Jerman juga menggunakan iso-8859-2 dan windows-1250 (latin2).

Mereka bentuk pengekodan aksara suapan RSS kelihatan rumit. Malah halaman web biasa sering meninggalkan atau berbohong tentang pengekodan mereka.

Jadi, anda boleh cuba menggunakan cara yang betul untuk mengesan pengekodan, dan kemudian kembali kepada beberapa bentuk pengesanan automatik (meneka).

Saya tahu ini adalah soalan lama, tetapi saya percaya jawapan yang berguna tidak pernah menyakitkan. Saya menghadapi masalah dengan pengekodan saya antara aplikasi desktop, pembolehubah SQLite dan GET/POST. Sebahagian daripada mereka akan berada dalam UTF-8, sebahagian daripada mereka akan berada dalam ASCII, dan kebanyakannya perkara akan menjadi mengelirukan apabila watak asing terlibat.

Inilah penyelesaian saya. Ia meratakan GET/POST/REQUEST anda (saya meninggalkan kuki, tetapi anda boleh menambahnya jika perlu) pada setiap pemuatan halaman sebelum diproses. Ia berfungsi dengan baik dalam pengepala. PHP akan mengeluarkan amaran jika ia tidak dapat menentukan pengekodan sumber secara automatik, jadi amaran ini ditindas menggunakan @.

//Tukar semua dalam vars kami kepada UTF-8 untuk bermain bagus dengan pangkalan data... //Gunakan beberapa pengesanan automatik di sini untuk membantu kami tidak mengekod dua kali... //Sekat amaran yang mungkin dengan @ apabila pengekodan tidak dapat dikesan cuba ($ proses = tatasusunan(&$_GET, &$_POST, &$_REQUEST); manakala (senarai($kunci, $val) = setiap ($proses)) ( foreach ($val sebagai $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)()

Saya telah menyemak penyelesaian pengekodan dengan AGES dan halaman ini mungkin penghujung tahun pencarian! Saya telah menyemak beberapa cadangan yang anda nyatakan dan berikut ialah nota saya:

Ini adalah baris ujian saya:

ini ialah baris "wròng wrìtten" yang saya tidak gunakan untuk mengkonfigurasi chàrs khas untuk melihat thèm, convertèd by fùnctìon!! Jadi apa ini!

Fon halaman saya ialah UTF-8

Jika saya INSERT cara ini, saya mempunyai beberapa aksara dalam DB saya yang mungkin berasal dari Marikh... jadi saya perlu menukarnya kepada UTF-8 yang "masuk akal". Saya mencuba utf8_encode() tetapi aksara asing masih menyerang pangkalan data saya...

Jadi, saya cuba menggunakan fungsi forceUTF8 yang terletak di nombor 8, tetapi dalam DB rentetan yang disimpan kelihatan seperti ini:

ini adalah rentetan "wròng wrìtten" bùt Saya terpaksa memberi "sò saya" chà rs khas untuk melihatnya, convertèd oleh fùnctìon!! Jadi apa ini!

Jadi, dengan mengumpul beberapa maklumat lanjut pada halaman ini dan menggabungkannya dengan maklumat lain pada halaman lain, saya menyelesaikan masalah dengan penyelesaian ini:

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

Sekarang dalam pangkalan data saya, saya mempunyai rentetan dengan pengekodan yang betul.

Catatan: Hanya nota untuk menjaga fungsi mysql_client_encoding! Anda mesti disambungkan ke DB kerana fungsi ini memerlukan ID sumber sebagai parameter.

Tetapi ok, saya hanya melakukan pengekodan semula ini sebelum INSERT saya, jadi ia tidak menjadi masalah bagi saya.

Saya harap ini membantu seseorang seperti halaman ini membantu saya!

Terima kasih semua!

Perkara yang menarik tentang mb_detect_encoding dan mb_convert_encoding ialah susunan pengekodan yang anda tawarkan adalah penting:

// $input sebenarnya adalah UTF-8 mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8"); // ISO-8859-9 (SALAH!) mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9"); // UTF-8 (OK)

Dengan cara ini anda boleh menggunakan susunan tertentu apabila menentukan pengekodan yang dijangkakan. Walau bagaimanapun, sedar bahawa ini tidak mudah.

Echo mb_detect_encoding($str, "auto");

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

Saya tidak begitu tahu keputusannya, tetapi saya cadangkan anda hanya mengambil beberapa saluran anda dengan pengekodan yang berbeza dan cuba jika mb_detect_encoding berfungsi atau tidak.

Kemas kini
auto ialah singkatan untuk "ASCII, JIS, UTF-8, EUC-JP, SJIS". ia mengembalikan pengekodan yang dikesan, yang boleh anda gunakan untuk menukar rentetan kepada utf-8 dengan iconv .

Saya belum mengujinya, jadi tiada jaminan. dan mungkin ada cara yang lebih mudah.

Versi ini adalah untuk bahasa Jerman, tetapi anda boleh mengubah suai $CHARSETS dan $TESTCHARS

Class CharsetDetector ( private static $CHARSETS = array("ISO_8859-1", "ISO_8859-15", "CP850"); private static $TESTCHARS = array("€", "ä", "Ä", "ö", "Ö", "ü", "Ü", "ß"); public static function convert($string) ( return self::__iconv($string, self::getCharset($string)); ) public static function getCharset ($rentetan) ($normal = diri::__normalize($string); if(!strlen($normal))kembali "UTF-8"; $best = "UTF-8"; $charcountbest = 0; foreach (diri sendiri ::$CHARSETS sebagai $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; ) //gema $teks."
"; ) kembalikan $best; ) fungsi statik peribadi __normalize($str) ( $len = strlen($str); $ret = ""; for($i = 0; $i< $len; $i++){ $c = ord($str[$i]); if ($c >128) ( jika (($c > 247)) $ret .=$str[$i]; elseif ($c > 239) $bait = 4; elseif ($c > 223) $bait = 3; elseif ($ c > 191) $bait = 2; lain $ret .=$str[$i]; jika (($i + $bait) > $len) $ret .=$str[$i]; $ret2=$str [$i]; manakala ($bait > 1) ($i++; $b = ord($str[$i]); jika ($b< 128 || $b >191) ($ret .=$ret2; $ret2=""; $i+=$bait-1;$bait=1; pecah;) lain $ret2.=$str[$i]; $bait--; ) ) ) pulangkan $ret; ) fungsi statik peribadi __iconv($string, $charset) ( return iconv ($charset, "UTF-8" , $string); ) )

Selepas menyusun skrip php anda, jangan lupa beritahu mysql pengekodan yang anda lalui dan ingin menerimanya.

Contoh: menetapkan set aksara kepada utf8

Menghantar data utf8 ke jadual latin1 dalam sesi I/O latin1 memberikan burung jahat ini. Saya melihat ini setiap hari di kedai runcit. Pergi dan balik mungkin kelihatan betul. Tetapi phpmyadmin akan menunjukkan kebenaran. Memberitahu mysql pengekodan yang anda lalui akan memproses data mysql untuk anda.

Bagaimana untuk memulihkan data hancur mysql sedia ada adalah soalan lain untuk perbincangan. :)