Php kuinka selvittää koodauskartoitus. Tekstin koodauksen määrittäminen PHP:ssä - yleiskatsaus olemassa oleviin ratkaisuihin ja vielä yksi pyörä. Mitä Google tuo esiin

Törmäsin ongelmaan - sivun/tekstin/mitä tahansa koodauksen automaattinen tunnistus. Tehtävä ei ole uusi, ja monia polkupyöriä on jo keksitty. Artikkeli sisältää lyhyen yleiskatsauksen siitä, mitä Internetistä löydettiin - sekä ehdotuksen mielestäni arvokkaasta ratkaisusta.

1. Miksei mb_detect_encoding()?

Lyhyesti sanottuna se ei toimi.

Katsotaan:
// Sisäänkäynnillä - venäjänkielinen teksti CP1251-koodauksessa $string = iconv("UTF-8", "Windows-1251", "Hän lähestyi Anna Pavlovnaa, suuteli tämän kättä paljastaen tuoksuisen ja kiiltävän kaljun päänsä tälle ja rauhallisesti istui sohvalle."); // Katsotaan mitä md_detect_encoding() antaa meille. Ensimmäinen $strict = EPÄTOSI 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 // Nyt $strict = TOSI var_dump(mb_detect_encoding($string, array("UTF-8", TRUE)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251"), TRUE)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "KOI8-R"), TOSI)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R"), TOSI)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"), TOSI)); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"), TRUE)); // ISO-8859-5
Kuten näette, tulos on täydellinen sotku. Mitä teemme, kun on epäselvää, miksi funktio käyttäytyy tällä tavalla? Aivan oikein, googletetaan. Löysin loistavan vastauksen.

Voit vihdoin hälventää kaikki toiveet mb_detect_encoding(:n) käytöstä, sinun on tutkittava mbstring-laajennuksen lähdekoodia. Kääri siis hihat ja mennään:
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // rivi 2703 ret = mbfl_identify_encoding_name(&merkkijono, elist, koko, tiukka); ...
Ctrl + napsautus:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:643 const char* mbfl_identify_encoding_name(mbfl_string *merkkijono, enum mbfl_no_encoding *elist, int elistsz, int strict) ( const mbfl_encoding *encoding (elcodingisttify_mb; flencodingisttring; flencodingisttring; , tiukka);
Ctrl + napsautus:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * tunnista koodaus */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *merkkijono, enum mbfl_no_encoding *elist, int elistsz, int strict) ( ...
En julkaise menetelmän koko tekstiä, jotta en sotke artikkelia tarpeettomilla lähteillä. Kiinnostuneet pääsevät katsomaan itse. Olemme kiinnostuneita rivistä 593, jossa tarkastamme, vastaako merkki koodausta:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, suodatin); jos (suodatin->lippu) ( huono++; )
Tässä ovat yksitavuisen kyrillisen kirjaimen pääsuodattimet:

Windows-1251 (alkuperäiset kommentit säilytetty)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* kaikki tämä on nyt niin rumaa! */ static int mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c< 0xff) filter->lippu = 0; muu suodatin->

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->lippu = 0; muuten suodatin->lippu = 1; /* ei se */ return c; )

ISO-8859-5 (täällä kaikki on hauskaa)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *filter) ( return c; )
Kuten näet, ISO-8859-5 palauttaa aina TRUE (jos haluat palauttaa arvon FALSE, sinun on asetettava suodatin->lippu = 1).

Kun katsoimme suodattimia, kaikki loksahti paikoilleen. CP1251:tä ei voida erottaa KOI8-R:stä. Yleensä ISO-8859-5, jos se on koodausluettelossa, tunnistetaan aina oikeaksi.

Yleensä epäonnistua. Tämä on ymmärrettävää - yleensä on mahdotonta selvittää koodausta vain merkkikoodeilla, koska nämä koodit leikkaavat eri koodauksia.

2. Mitä Google tuo esiin

Ja Google tuo esiin kaikenlaista kurjuutta. En edes laita lähdettä tänne, katso itse, jos haluat (poista välilyönnit http:// jälkeen, en osaa näyttää tekstiä ilman linkkiä):

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

3. Hae keskittimen mukaan

1) jälleen merkkikoodit: habrahabr.ru/blogs/php/27378/#comment_710532

2) mielestäni erittäin mielenkiintoinen ratkaisu: habrahabr.ru/blogs/php/27378/#comment_1399654
Plussat ja miinukset linkin kommentissa. Henkilökohtaisesti uskon, että tämä ratkaisu on tarpeeton vain koodauksen havaitsemiseen - se osoittautuu liian tehokkaaksi. Koodauksen määrittäminen siihen on sivuvaikutus).

4. Itse asiassa minun päätökseni

Idea syntyi katsoessa edellisen osion toista linkkiä. Idea on seuraava: otamme suuren venäjän tekstin, mittaamme eri kirjainten taajuudet ja käytämme näitä taajuuksia koodauksen havaitsemiseen. Tulevaisuudessa sanon heti, että suurilla ja pienillä kirjaimilla on ongelmia. Siksi julkaisen esimerkkejä kirjainten taajuuksista (kutsutaanko sitä "spektriksi"), sekä isot ja pienet kirjaimet erottuvat (toisessa tapauksessa lisäsin pieneen kirjaimeen vielä suuremman samalla taajuudella ja poistin kaikki isommat). Näistä "spektreistä" leikataan pois kaikki kirjaimet, joiden taajuudet ovat alle 0,001 ja välilyönti. Tämän sain käsiteltyäni "War and Peace":

Kirjainkoolla erottuva "spektri":
taulukko ("o" => 0,095249209893009, "e" => 0,06836817536026, "a" => 0,067481298384992, "i" => 0,05599502740004 "e" => 0,002252892226507, "N " => 0,0021318391371162, "P" => 0,0018574762967903, "f" => 0,0015961610948418, "B" => 0,001404433297573 = 7,8,8,8,0,8,0 "A" => 0,0012623590130186, "K" => 0,0011804488387602, "M" => 0,001061932790165,)

Kirjainkoosta riippumaton:
taulukko ("O" => 0,095249209893009, "o" => 0,095249209893009, "E" => 0,06836817536026, "e" => 0,06836817536026, 8,8,8,8,8 " => 0,067481298384992, "JA" => 0,055995027400041 , "i" => 0,055995027400041, .... "C" => 0,0029893589260344, "c" => 0,0029893589260344, "c" => 0,0024649166, 6 1406, "E" => 0,002252892226507, "e " => 0,002252892226507, "F" => 0,0015961610948418, "f" => 0,0015961610948418,)

Spektrit eri koodauksissa (taulukkonäppäimet ovat vastaavien merkkien koodeja sopivassa koodauksessa):

Edelleen. Otamme tekstin tuntemattomasta koodauksesta, jokaiselle tarkistettavalle koodaukselle löydämme nykyisen merkin taajuuden ja lisäämme sen tämän koodauksen "luokitukseen". Koodaus, jolla on korkein arvosana, on todennäköisesti tekstikoodaus.

$encodings = array("cp1251" => vaatia "specter_cp1251.php", "koi8r" => vaatia "specter_koi8r.php", "iso88595" => vaatia "specter_iso88595.php"); $enc_hinnat = array(); for ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ( $enc_rates[$koodaus] += $char_specter)]; ) ) var_dump($enc_rates);
Älä edes yritä suorittaa tätä koodia itse - se ei toimi. Voit harkita tätä pseudokoodia - olen jättänyt yksityiskohdat pois, jotta en sotke artikkelia. $char_specter ovat täsmälleen ne taulukot, joihin pastebinissa viitataan.

tuloksia
Taulukon rivit ovat tekstin koodausta, sarakkeet ovat $enc_rates-taulukon sisältöä.

1) $str = "venäjänkielinen teksti";
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

Kaikki on hyvin. Oikealla koodauksella on jo 4 kertaa korkeampi arvosana kuin muilla - tämä on niin lyhyt teksti. Pidemmillä teksteillä suhde on suunnilleen 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

Oho! Täysi sotku. Tämä johtuu siitä, että CP1251:n suuret kirjaimet vastaavat yleensä KOI8-R:n pieniä kirjaimia. Ja pieniä kirjaimia puolestaan ​​käytetään paljon useammin kuin suuria. Joten määrittelemme caps-merkkijonon CP1251:ssä nimellä KOI8-R.
Yritetään tehdä se kirjainkoolla välinpitämättömästi ("spektrit" ei välitä kirjainkoosta)

1) $str = "venäjänkielinen teksti";
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 = "VENÄJÄN TEKSTI JOULUKAISIKOIMILLA";
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

Kuten näet, oikea koodaus johtaa johdonmukaisesti sekä isot ja pienet kirjaimet erottelevilla "spektreillä" (jos rivillä on pieni määrä isoja kirjaimia). Toisessa tapauksessa, kirjainkoolla ei ole merkitystä, johto ei tietenkään ole niin varma, mutta melko vakaa jopa pienillä linjoilla. Voit myös leikkiä kirjainten painoilla - tehdä niistä epälineaarisia esimerkiksi taajuuden suhteen.

5. Päätelmät

Aihe ei kata työskentelyä UTF-8:n kanssa - tässä ei ole perustavanlaatuista eroa, paitsi että merkkikoodien saaminen ja merkkijonon jakaminen merkeiksi on hieman pidempää/monimutkaisempaa.
Näitä ajatuksia ei voi tietysti laajentaa pelkästään kyrillisiin koodauksiin - kysymys on vain vastaavien kielten/koodausten "spektreistä".

P.S. Jos se on todella tarpeellista / mielenkiintoista, julkaisen täysin toimivan kirjaston toisen osan GitHubissa. Vaikka uskon, että viestin tiedot ovat aivan riittävät kirjoittamaan nopeasti tällainen kirjasto omiin tarpeisiisi - venäjän kielen "spektri" on laadittu, se voidaan helposti siirtää kaikkiin tarvittaviin koodauksiin.

Törmäsin ongelmaan - sivun/tekstin/mitä tahansa koodauksen automaattinen tunnistus. Tehtävä ei ole uusi, ja monia polkupyöriä on jo keksitty. Artikkeli sisältää lyhyen yleiskatsauksen siitä, mitä Internetistä löydettiin - sekä ehdotuksen mielestäni arvokkaasta ratkaisusta.

1. Miksei mb_detect_encoding()?

Lyhyesti sanottuna se ei toimi.

Katsotaan:
// Sisäänkäynnillä - venäjänkielinen teksti CP1251-koodauksessa $string = iconv("UTF-8", "Windows-1251", "Hän lähestyi Anna Pavlovnaa, suuteli tämän kättä paljastaen tuoksuisen ja kiiltävän kaljun päänsä tälle ja rauhallisesti istui sohvalle."); // Katsotaan mitä md_detect_encoding() antaa meille. Ensimmäinen $strict = EPÄTOSI 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 // Nyt $strict = TOSI var_dump(mb_detect_encoding($string, array("UTF-8", TRUE)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251"), TRUE)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "KOI8-R"), TOSI)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R"), TOSI)); // EPÄTOSI var_dump(mb_detect_encoding($string, array("UTF-8", "ISO-8859-5"), TOSI)); // ISO-8859-5 var_dump(mb_detect_encoding($string, array("UTF-8", "Windows-1251", "KOI8-R", "ISO-8859-5"), TRUE)); // ISO-8859-5
Kuten näette, tulos on täydellinen sotku. Mitä teemme, kun on epäselvää, miksi funktio käyttäytyy tällä tavalla? Aivan oikein, googletetaan. Löysin loistavan vastauksen.

Voit vihdoin hälventää kaikki toiveet mb_detect_encoding(:n) käytöstä, sinun on tutkittava mbstring-laajennuksen lähdekoodia. Kääri siis hihat ja mennään:
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // rivi 2703 ret = mbfl_identify_encoding_name(&merkkijono, elist, koko, tiukka); ...
Ctrl + napsautus:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:643 const char* mbfl_identify_encoding_name(mbfl_string *merkkijono, enum mbfl_no_encoding *elist, int elistsz, int strict) ( const mbfl_encoding *encoding (elcodingisttify_mb; flencodingisttring; flencodingisttring; , tiukka);
Ctrl + napsautus:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * tunnista koodaus */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *merkkijono, enum mbfl_no_encoding *elist, int elistsz, int strict) ( ...
En julkaise menetelmän koko tekstiä, jotta en sotke artikkelia tarpeettomilla lähteillä. Kiinnostuneet pääsevät katsomaan itse. Olemme kiinnostuneita rivistä 593, jossa tarkastamme, vastaako merkki koodausta:
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, suodatin); jos (suodatin->lippu) ( huono++; )
Tässä ovat yksitavuisen kyrillisen kirjaimen pääsuodattimet:

Windows-1251 (alkuperäiset kommentit säilytetty)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* kaikki tämä on nyt niin rumaa! */ static int mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c< 0xff) filter->lippu = 0; muu suodatin->

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->lippu = 0; muuten suodatin->lippu = 1; /* ei se */ return c; )

ISO-8859-5 (täällä kaikki on hauskaa)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *filter) ( return c; )
Kuten näet, ISO-8859-5 palauttaa aina TRUE (jos haluat palauttaa arvon FALSE, sinun on asetettava suodatin->lippu = 1).

Kun katsoimme suodattimia, kaikki loksahti paikoilleen. CP1251:tä ei voida erottaa KOI8-R:stä. Yleensä ISO-8859-5, jos se on koodausluettelossa, tunnistetaan aina oikeaksi.

Yleensä epäonnistua. Tämä on ymmärrettävää - yleensä on mahdotonta selvittää koodausta vain merkkikoodeilla, koska nämä koodit leikkaavat eri koodauksia.

2. Mitä Google tuo esiin

Ja Google tuo esiin kaikenlaista kurjuutta. En edes laita lähdettä tänne, katso itse, jos haluat (poista välilyönnit http:// jälkeen, en osaa näyttää tekstiä ilman linkkiä):

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

3. Hae keskittimen mukaan

1) jälleen merkkikoodit:

2) mielestäni erittäin mielenkiintoinen ratkaisu:
Plussat ja miinukset linkin kommentissa. Henkilökohtaisesti uskon, että tämä ratkaisu on tarpeeton vain koodauksen havaitsemiseen - se osoittautuu liian tehokkaaksi. Koodauksen määrittäminen siihen on sivuvaikutus).

4. Itse asiassa minun päätökseni

Idea syntyi katsoessa edellisen osion toista linkkiä. Idea on seuraava: otamme suuren venäjän tekstin, mittaamme eri kirjainten taajuudet ja käytämme näitä taajuuksia koodauksen havaitsemiseen. Tulevaisuudessa sanon heti, että suurilla ja pienillä kirjaimilla on ongelmia. Siksi julkaisen esimerkkejä kirjainten taajuuksista (kutsutaanko sitä "spektriksi"), sekä isot ja pienet kirjaimet erottuvat (toisessa tapauksessa lisäsin pieneen kirjaimeen vielä suuremman samalla taajuudella ja poistin kaikki isommat). Näistä "spektreistä" leikataan pois kaikki kirjaimet, joiden taajuudet ovat alle 0,001 ja välilyönti. Tämän sain käsiteltyäni "War and Peace":

Kirjainkoolla erottuva "spektri":
taulukko ("o" => 0,095249209893009, "e" => 0,06836817536026, "a" => 0,067481298384992, "i" => 0,05599502740004 "e" => 0,002252892226507, "N " => 0,0021318391371162, "P" => 0,0018574762967903, "f" => 0,0015961610948418, "B" => 0,001404433297573 = 7,8,8,8,0,8,0 "A" => 0,0012623590130186, "K" => 0,0011804488387602, "M" => 0,001061932790165,)

Kirjainkoosta riippumaton:
taulukko ("O" => 0,095249209893009, "o" => 0,095249209893009, "E" => 0,06836817536026, "e" => 0,06836817536026, 8,8,8,8,8 " => 0,067481298384992, "JA" => 0,055995027400041 , "i" => 0,055995027400041, .... "C" => 0,0029893589260344, "c" => 0,0029893589260344, "c" => 0,0024649166, 6 1406, "E" => 0,002252892226507, "e " => 0,002252892226507, "F" => 0,0015961610948418, "f" => 0,0015961610948418,)

Spektrit eri koodauksissa (taulukkonäppäimet ovat vastaavien merkkien koodeja sopivassa koodauksessa):

Edelleen. Otamme tekstin tuntemattomasta koodauksesta, jokaiselle tarkistettavalle koodaukselle löydämme nykyisen merkin taajuuden ja lisäämme sen tämän koodauksen "luokitukseen". Koodaus, jolla on korkein arvosana, on todennäköisesti tekstikoodaus.

$encodings = array("cp1251" => vaatia "specter_cp1251.php", "koi8r" => vaatia "specter_koi8r.php", "iso88595" => vaatia "specter_iso88595.php"); $enc_hinnat = array(); for ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ( $enc_rates[$koodaus] += $char_specter)]; ) ) var_dump($enc_rates);
Älä edes yritä suorittaa tätä koodia itse - se ei toimi. Voit harkita tätä pseudokoodia - olen jättänyt yksityiskohdat pois, jotta en sotke artikkelia. $char_specter ovat täsmälleen ne taulukot, joihin pastebinissa viitataan.

tuloksia
Taulukon rivit ovat tekstin koodausta, sarakkeet ovat $enc_rates-taulukon sisältöä.

1) $str = "venäjänkielinen teksti";
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

Kaikki on hyvin. Oikealla koodauksella on jo 4 kertaa korkeampi arvosana kuin muilla - tämä on niin lyhyt teksti. Pidemmillä teksteillä suhde on suunnilleen 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

Oho! Täysi sotku. Tämä johtuu siitä, että CP1251:n suuret kirjaimet vastaavat yleensä KOI8-R:n pieniä kirjaimia. Ja pieniä kirjaimia puolestaan ​​käytetään paljon useammin kuin suuria. Joten määrittelemme caps-merkkijonon CP1251:ssä nimellä KOI8-R.
Yritetään tehdä se kirjainkoolla välinpitämättömästi ("spektrit" ei välitä kirjainkoosta)

1) $str = "venäjänkielinen teksti";
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 = "VENÄJÄN TEKSTI JOULUKAISIKOIMILLA";
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

Kuten näet, oikea koodaus johtaa johdonmukaisesti sekä isot ja pienet kirjaimet erottelevilla "spektreillä" (jos rivillä on pieni määrä isoja kirjaimia). Toisessa tapauksessa, kirjainkoolla ei ole merkitystä, johto ei tietenkään ole niin varma, mutta melko vakaa jopa pienillä linjoilla. Voit myös leikkiä kirjainten painoilla - tehdä niistä epälineaarisia esimerkiksi taajuuden suhteen.

5. Päätelmät

Aihe ei kata työskentelyä UTF-8:n kanssa - tässä ei ole perustavanlaatuista eroa, paitsi että merkkikoodien saaminen ja merkkijonon jakaminen merkeiksi on hieman pidempää/monimutkaisempaa.
Näitä ajatuksia ei voi tietysti laajentaa pelkästään kyrillisiin koodauksiin - kysymys on vain vastaavien kielten/koodausten "spektreistä".

P.S. Jos se on todella tarpeellista / mielenkiintoista, julkaisen täysin toimivan kirjaston toisen osan GitHubissa. Vaikka uskon, että viestin tiedot ovat aivan riittävät kirjoittamaan nopeasti tällainen kirjasto omiin tarpeisiisi - venäjän kielen "spektri" on laadittu, se voidaan helposti siirtää kaikkiin tarvittaviin koodauksiin.

Idea - Lotto

En keksinyt ideaa koodauksen hankkimisesta, mutta valitettavasti en voi nyt kertoa kirjoittajaa, koska siitä on noin 4 vuotta ja mistä nämä tiedot sain, on unohdettu pitkään. Kirjoittaja ehdotti määritelmää ja näytti esimerkin 1-2 koodauksesta Pythonissa. Hänen ratkaisunsa yksinkertaisuus ei jättänyt minua sivuun, ja kehitin sen haluttuun lopputulokseen.
Idean ydin piilee itse koodauskooditaulukoissa. Kuten tiedät, jokainen koodaus sisältää oman kooditaulukon ja jokaiselle koodausmerkille on määritetty tietty arvo. En näytä tässä koodaustaulukoita, nyt ne ovat melko helppoja löytää Internetistä.
Toteutusperiaate on seuraava:
  1. Taulukkomuuttuja luodaan tallentamaan tarkistetun tekstin "analyysin" tulos. Jokainen taulukkoelementti sisältää tietyn koodauksen tuloksen.
  2. Toiminnon syötteenä vastaanotettu teksti iteroidaan symbolisesti.
  3. Järjestysluku (tämän merkin merkitys) otetaan jokaisesta merkistä ja sitä verrataan koodausalueeseen.
  4. Jos arvo osuu isoon kirjaimeen, arvo 1 lisätään taulukkoelementtiin, joka tallentaa tämän koodauksen tuloksen.
  5. Jos arvo osuu pieniin kirjaimiin, arvo 3 lisätään taulukkoelementtiin, joka tallentaa tämän koodauksen tuloksen.
  6. Tuo koodaus tai tarkemmin sanottuna taulukon elementti, joka tallentaa sen koodauksen tuloksen ja joka sai eniten pisteitä, on todennäköisesti alkuperäinen koodaus.
Tämä algoritmi soveltuu yksitavuisille koodauksille, kuten KOI-8, CP1251 (windows-1251) ja muille. Kaksitavuisille koodauksille (tapauksessani UTF-8) tämä lähestymistapa tuottaa kuitenkin virheellisen tuloksen. Aluksi yritin ratkaista tämän ongelman lisäämällä 5 isoja merkkejä ja 7 pieniä merkkejä. Tulos parani, mutta tunnistusvirheitä oli edelleen. Kokeilun jälkeen päätin, että UTF:n määrittämiseksi oikein isojen kirjainten kohdalla tulokseen tulisi lisätä 10, pienille kirjaimille 14, eli 2 kertaa enemmän kuin alkuperäinen arvaukseni. Kuitenkin koodin paremman visuaalisen ymmärtämisen vuoksi jätin UTF-merkeille 5 ja 7, ja testauksen aikana lisäsin näitä arvoja 2:lla ja lisäsin ne tulokseen.
Se on pohjimmiltaan koko algoritmi. Ja ilman turhaa vaivaa.
Suurin osa ajasta, jonka käytin tämän toiminnon toteuttamiseen, oli tietysti kooditaulukoiden etsiminen ja alueiden oikea järjestys. Sen lisäksi, että nykyisen kooditaulukon löytäminen oli melko vaikeaa, kun kirjoitin tämän funktion ensimmäisen kerran, myös niiden merkkialueet hyppäävät satunnaisesti. Sen jälkeen päädyin kuitenkin uusimpiin (ja tähän päivään asti) koodauksiin: UTF-8, CP1251, KOI8-R, IBM866, ISO-8859-5 ja MAC. Jos nämä koodaukset eivät riitä sinulle, voit täydentää koodia tämän algoritmin perusteella.

Sanoista käytäntöön

Itse asiassa koko toimintokoodi Pythonissa näyttää tältä:

Koodaukset = ( "UTF-8": "utf-8", "CP1251": "windows-1251", "KOI8-R": "koi8-r", "IBM866": "ibm866", "ISO-8859- 5": "iso-8859-5", "MAC": "mac", ) """ Tekstikoodauksen määrittäminen """ def get_codepage(str = Ei mitään): isot kirjaimet = 1 pienet = 3 utfupper = 5 utflower = 7 codepages = () for enc in encodings.keys(): koodisivut = 0, jos str ei ole Ei mitään ja len(str) > 0: last_simb = 0 for simb in str: simb_ord = ord(simb) """muita kuin venäläisiä merkkejä " "" jos simb_ord< 128 or simb_ord >256: jatka """UTF-8""" jos last_simb == 208 ja (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 = koodisivut idx = tuotteen palautustunnus
Esimerkki funktiokutsusta

Tulosta koodaukset

Entä PHP?

Valmiin funktion uudelleenkirjoittaminen Pythonista PHP:hen ei ollut vaikeaa. Ulkonäöltään se ei käytännössä eroa Python-emästä:

/** * Määritä tekstin koodaus * @param String $text Text * @return String Tekstin koodaus */ funktio get_codepage($text = "") ( if (!empty($text)) ( $utflower = 7; $utfupper $pienet kirjaimet = 1; $last_simb = 0, "CP1251" => 0, "IBM866"; > 0, "ISO-8859-5" => 0, "MAC" => 0, ($a = 0; $a< strlen($text); $a++) { $char = ord($text[$a]); // non-russian characters if ($char<128 || $char>256) jatka; // UTF-8 if (($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); } }
Esimerkki funktiokutsusta

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

LikBez tai Älä häiritse koneen työtä

Sinun ei pitäisi yrittää törmäystestiä tätä toimintoa. Algoritmista käy selvästi ilmi, että mitä vähemmän tekstiä se vastaanottaa syötteenä, sitä suurempi on todennäköisyys, että funktio tunnistaa koodauksen väärin. Toisaalta Leo Tolstoin ruokinnassa ei myöskään ole mitään järkeä: tämä menetelmä selviää hyvin pienestä 100-200 merkin lauseesta. Ja vaikka kutsun esimerkeissä syötteeseen lähetin tietyn tiedoston "test.txt" koko sisällön, jonka piti sisältää tekstiä, jonka koodaus on määritettävä, pieni osa tekstiä voidaan (ja pitäisi) olla siirretty funktion tuloon.
Pidän isoja ja pieniä kirjaimia sekoitettuja perversioita yleensä tässä tapauksessa sopimattomina, koska tämä menetelmä on kirjoitettu tavalliseen, rullatehtävään suunnilleen lukutaitoisella venäjän kielellä. Ja tällaiset kokeet muistuttavat minua useimmiten vitsistä:

Venäläinen puunjalostuslaitos osti japanilaisen yksikön. Venäläiset työntekijät kokoontuivat hänen ympärilleen ja pohditaan kuinka hän toimii. Yksi otti laudan ja työnsi sen siihen. Yksikkö:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz... Pojat: Vau!!! Yksikkö esillä: no, mitä ajattelit? Toinen otti puun ja työnsi sen yksikköön. Yksikkö:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzsen... Lopputulos on valmis veistetty senkki. Pojat: Vau!!! Yksikkö esillä: no, mitä ajattelit? Kolmas mies ei kestänyt sitä, veti jostain kaiteen ja työnsi sen yksikköön. Yksikkö: drrrrrrr-tyh-tyh-tyh... Se alkoi savuta ja näytössä lukee: Vau!!! Kaverit: no mitä ajattelit!!!
Joten tällaisia ​​kierrettyjä testejä varten tarvitset todennäköisesti kierretyn algoritmin, jota tämä toiminto ei ole. Ja käytännössä sanon, että 4 vuoden käytön aikana tämä menetelmä ei ole koskaan pettänyt minua ja antanut aina oikean tuloksen.
Toivon, että artikkelini on hyödyllinen jollekin.
Kiitos huomiostasi.

Kun käytät kaikkea tai osaa siitä, älä unohda antaa linkki lähteeseen, eli blogiini.

On ilmennyt ongelma: kuinka nopeasti määrittää tekstijonon koodaus suhteessa UTF-8:aan. Yhä useammin joudumme työskentelemään merkkijonojen kanssa UNICODE-koodauksessa.

Alla on toiminto, joka tarkistaa, onko UNICODE (UTF-8) -koodaus muutettava WINDOWS (win-1251) -koodaukseksi

Funktio antaa melko tarkan vastauksen, vaikka se ei perustu merkkikohtaiseen muuntamiseen.

toiminto detect_my_utf($s)( $s=urlencode($s); // joissakin tapauksissa - tarpeeton toiminto (kommentti ulos) $res="0"; $j=strlen($s); $s2=strtoupper($ s) $s2=str_replace("%D0","$s2=str_replace("%D1","",$s2)($m=$j/); $k; if (($m>1.2)&&($m

Toiminnon lyhyt kuvaus detect_my_utf():

  • muuntaa (merkkijono erikoismuotoon)
  • laskea saapuvan merkkijonon pituus
  • kirjoita kaikki merkkijonon kirjaimet isoilla
  • poista tietyt koodit %D0 ja %D1
  • laske uuden rivin pituus
  • saamme vanhan rivin suhteen uuteen

Jos tämä suhde on 1 tai lähellä sitä, epäillään, että saapuvaa merkkijonoa ei ole koodattu UNICODE:lla. Jos tämä suhde on välillä 1,2–2,2, voit turvallisesti koodata merkkijonon uudelleen WINDOWS win-1251 -koodaukseksi.

Toiminnon lähtö on 0 tai 1, ei UNICODE tai UNICODE.

Esimerkkejä funktion suorittamisesta:

Saapuva linja: РїР?С?С?Р?Р?Рє С?Р?Р·Р?Р°Р?РёС? Р°Р?РёР?Р°С+РёРё Р? imageready Muunnettu merkkijono: %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 Toiminnon tulos: 1 Koodattu lause: animaation luontijärjestys imagereadyssa

Saapuva merkkijono: R?S?R?R?R?S

Saapuva merkkijono: РїС?Р?Р?С?Р°Р?Р?Р° С+С"РчР?РёС? РїР?С+Р°С?апаР?Р?С

Syöttömerkkijono: piirustusopas Muunnettu merkkijono: %EF%EE%F1%EE%E1%E8%E5 %EF%EE %F0%E8%F1%EE%E2%E0%ED%E8%FE Funktiotulos: 0 Koodattu lause : piirustusopas Tämä algoritmi selviää hyvin erilaisista saapuvista merkkijonoista osana hakukoneen tulostilastopalvelua.

Mielenkiintoisia materiaaleja sivustolla:

  • Artikkeli sivuston hakukoneen kiinnostavuudesta. Ehkä osa materiaaleista on vanhentunut jo 10 vuoden jälkeen, mutta joihinkin seikkoihin kannattaa kiinnittää huomiota.

  • Sinun näkemyksesi ongelmasta, joka liittyy hyperlinkkien vaihtamiseen luovuttajasivuston ja vastaanottajasivustojen välillä.

  • Toinen elämänmurto. Voitimme epärehelliset pelaajat pelissä "Balda". Suuri tietokanta sanoja, joita voidaan helposti laajentaa.

Luen paljon tekstejä eri RSS-syötteistä ja lisään ne tietokantaani.

Tietysti putkissa käytetään useita erilaisia ​​merkkikoodeja, mm. UTF-8 ja ISO-8859-1.

Valitettavasti joskus tekstin koodauksissa ilmenee ongelmia. Esimerkki:

1) "ß":n "Fußball":ssa pitäisi näyttää tietokannassani tältä: "Ÿ". Jos se on "Ÿ", se näkyy oikein.

2) Joskus "Fußballin" "ß" näyttää tietokannassani tältä: "ß". Sitten se tietysti näkyy väärin.

3) Muissa tapauksissa "ß" tallennetaan nimellä "ß" - siis ilman muutoksia. Silloin se myös näkyy väärin.

Mitä voin tehdä välttääkseni tapaukset 2 ja 3?

Kuinka voin tehdä kaikesta saman koodauksen, mieluiten UTF-8? Milloin minun pitäisi käyttää utf8_encode(), milloin minun pitäisi käyttää utf8_decode() (tehoste on selvä, mutta milloin minun pitäisi käyttää funktioita?), ja milloin minun pitäisi tehdä jotain syötteellä?

Voitko auttaa minua ja kertoa kuinka tehdä kaikki sama koodaus? Ehkä mb-detect-encoding()-funktiolla? Voinko kirjoittaa funktion tälle? Ongelmani ovat siis: 1) Kuinka saada selville mitä koodausta tekstissä käytetään 2) kuinka muuntaa se UTF-8:ksi - vanhasta koodauksesta riippumatta

MUOKATA: Toimiiko tämä ominaisuus?

Funktio right_encoding($text) ( $current_encoding = mb_detect_encoding($teksti, "auto"); $teksti = iconv($current_encoding, "UTF-8", $teksti); palauttaa $teksti; )

Testasin mutta ei toimi. Mikä häntä vaivaa?

24 vastausta

Jos käytät utf8_encode():ta jo olemassa olevaan UTF8-merkkijonoon, se palauttaa vääristyneen UTF8-tulosteen.

Loin toiminnon, joka ratkaisee kaikki nämä ongelmat. Sitä kutsutaan Koodaukseksi::toUTF8().

Sinun ei tarvitse tietää, mikä merkkijonojesi koodaus on. Tämä voi olla Latin1 (iso 8859-1), Windows-1252 tai UTF8, tai merkkijono voi sisältää ne. Encoding::toUTF8() muuntaa kaiken UTF8:ksi.

Tein tämän, koska palvelu antoi minulle tietovirran, kaikki sekaisin, sekoittaen UTF8:n ja Latin1:n yhdellä rivillä.

Käyttö:

Require_once("Koodaus.php"); käytä \ForceUTF8\Encoding; // Se on nyt nimivälillä. $utf8_string = Koodaus::toUTF8($utf8_or_latin1_tai_mixed_string); $latin1_string = Koodaus::toLatin1($utf8_or_latin1_tai_mixed_string);

Olen lisännyt toisen funktion, Encoding::fixUFT8(), joka korjaa jokaisen UTF8-merkkijonon, joka näyttää sekaiselta.

Käyttö:

Require_once("Koodaus.php"); käytä \ForceUTF8\Encoding; // Se on nyt nimivälillä. $utf8_string = Koodaus::fixUTF8($garbled_utf8_string);

Kaikukoodaus::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

Päivitys: Muunsin funktion (forceUTF8) staattisten funktioiden perheeksi Encoding-luokassa. Uusi toiminto - Koodaus::toUTF8().

Ensin sinun on määritettävä, mitä koodausta käytettiin. Koska olet jäsentämässä RSS-syötteitä (mahdollisesti HTTP:n kautta), sinun tulee lukea koodaus HTTP-otsikon Content-Type-kentän charset-parametrista. Jos se puuttuu, lue koodaus käsittelykäskyn encoding-attribuutista. Jos myös tämä puuttuu, käytä UTF-8:aa spesifikaation mukaisesti.

Muuttaa Tässä on mitä luultavasti teen:

Koodauksen tunnistaminen on vaikeaa.

mb_detect_encoding toimii arvaamalla useiden hyväksymiesi ehdokkaiden perusteella. Joissakin koodauksissa tietyt tavusekvenssit ovat virheellisiä, joten se pystyy erottamaan eri ehdokkaat. Valitettavasti on monia koodauksia, joissa samat tavut ovat kelvollisia (mutta erilaisia). Näissä tapauksissa on mahdotonta määrittää koodausta; Voit toteuttaa omaa logiikkaasi tehdäksesi arvauksia näissä tapauksissa. Esimerkiksi japanilaisesta sivustosta tulevat tiedot ovat todennäköisesti japanilaisessa koodauksessa.

Kun käsittelet vain Länsi-Euroopan kieliä, katsotaanpa kolmea pääkoodausta: utf-8, iso-8859-1 ja cp-1252. Koska nämä ovat oletusarvoja monille alustoille, ne myös todennäköisesti raportoidaan virheellisesti. Esimerkiksi. jos ihmiset käyttävät erilaisia ​​koodauksia, he ovat luultavasti avoimia siitä, koska muuten heidän ohjelmistonsa rikkoutuvat hyvin usein. Joten hyvä strategia on luottaa palveluntarjoajaan, ellei koodausta ole ilmoitettu yhdeksi näistä kolmesta. Sinun tulisi silti kaksinkertaistaa sen tosiasiallinen kelpoisuus käyttämällä mb_check_encodingia (huomaa, että validi ei ole sama kuin on - sama syöte voi olla kelvollinen useille koodauksille). Jos se on yksi niistä, voit käyttää mb_detect_encodingia erottamaan ne toisistaan. Onneksi tämä on melko determinististä; Sinun tarvitsee vain käyttää oikeaa tunnistussekvenssiä, joka on UTF-8, ISO-8859-1, WINDOWS-1252.

Kun olet löytänyt koodauksen, sinun on muutettava se sisäiseen esitykseen (utf-8 on ainoa järkevä valinta). Funktio utf8_encode muuntaa iso-8859-1:n utf-8:ksi, joten sitä voidaan käyttää vain kyseiselle tulotyypille. Käytä muita koodauksia varten mb_convert_encoding.

Tämä huijauslehti sisältää joitain yleisiä varoituksia, jotka liittyvät UTF-8:n käsittelyyn PHP:ssä: http://developer.loftdigital.com/blog/php-utf-8-cheatsheet

Tämä toiminto, joka havaitsee merkkijonon monitavuiset merkit, voi myös olla hyödyllinen ():

Funktio detectUTF8($string) ( return preg_match("%(?: [\xC2-\xDF][\x80-\xBF] # ei-ylipitkä 2-tavuinen |\xE0[\xA0-\xBF][\x80- \xBF] # pois lukien ylipituudet |[\xE1-\xEC\xEE\xEF][\x80-\xBF](2) # suora 3-tavuinen |\xED[\x80-\x9F][\x80-\xBF] # ilman korvikkeita |\xF0[\x90-\xBF][\x80-\xBF](2) # tasoa 1-3 |[\xF1-\xF3][\x80-\xBF](3) # tasoa 4- 15 |\xF4[\x80-\x8F][\x80-\xBF](2) # taso 16)+%xs", $string); )

Hieman varoitus, sanoit, että "ß" pitäisi näkyä "Ÿ" tietokannassasi.

Tämä johtuu luultavasti siitä, että käytät tietokantaa latin1-merkkikoodauksella tai ehkä php-mysql-yhteyttä ei ole määritetty oikein, php olettaa, että mysql on määritetty käyttämään utf-8:aa, joten se lähettää tiedot muodossa utf8, mutta mysql uskoo, että php lähettää tiedot koodattuina iso-8859-1, joten se voi yrittää koodata lähetetyt tiedot uudelleen utf-8:ksi aiheuttaen tämän kaltaisia ​​ongelmia.

Katso tämä, se saattaa auttaa sinua: http://php.net/manual/en/function.mysql-set-charset.php

Sinun on tarkistettava tulon koodaus, koska vastaukset voivat olla koodattuja eri koodauksilla.
Pakotan kaiken sisällön lähetettäväksi UTF-8-muodossa tekemällä tunnistuksen ja kääntämisen seuraavalla toiminnolla:

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

Tämä toimenpide muuntaa kaikki etäisännästä tulevat PHP-muuttujat UTF-8:ksi.
Tai ohita arvo, jos koodausta ei voida havaita tai muuntaa.
Voit muokata sitä tarpeidesi mukaan.
Kutsu se vain ennen muuttujien käyttöä.

Koodauksesi näyttää siltä, ​​että olet koodattu UTF-8:lla kahdesti; eli jostain muusta koodauksesta UTF-8:aan ja uudelleen UTF-8:aan. Tuntuu kuin iso-8859-1 olisi muunnettu iso-8859-1:stä utf-8:ksi ja käsitelty rivinvaihdolla nimellä iso-8859-1 toista muunnosa varten UTF-8:ksi.

Tässä on pseudokoodi tekemiisi tekoihin:

$syötemerkkijono = getFromUser(); $utf8string = iconv($nykyinen_koodaus, "utf-8", $syötemerkkijono); $flawedstring = iconv($current_encoding, "utf-8", $utf8string);

Sinun täytyy yrittää:

  • Tunnista koodaus koodauksella mb_detect_encoding() tai mitä tahansa haluat käyttää
  • jos UTF-8, muunna muotoon iso-8859-1 ja toista vaihe 1
  • muuntaa lopulta takaisin UTF-8:ksi

Oletetaan, että "keskimääräisessä" muunnoksessa käytit iso-8859-1:tä. Jos käytit Windows-1252:ta, muunna Windows-1252:ksi (latin1). Lähteen alkuperäinen koodaus ei ole tärkeä; jota käytit virheellisessä toisessa muunnoksessa.

Tämä on minun arvaukseni tapahtuneesta; voit tehdä hieman enemmän saadaksesi neljä tavua yhden laajennetun ASCII-tavun sijaan.

Saksassa käytetään myös iso-8859-2 ja windows-1250 (latin2).

RSS-syötteiden merkkikoodauksen suunnittelu näyttää monimutkaiselta. Jopa tavalliset verkkosivut jättävät usein pois koodauksensa tai valehtelevat siitä.

Joten voit yrittää käyttää oikeaa tapaa havaita koodaus ja sitten palata johonkin automaattiseen havaitsemiseen (arvaukseen).

Tiedän, että tämä on vanha kysymys, mutta uskon, että hyödyllinen vastaus ei koskaan tee pahaa. Minulla on ongelmia koodaukseni kanssa työpöytäsovellusten, SQLite- ja GET/POST-muuttujien välillä. Osa niistä on UTF-8, osa ASCII-muodossa, ja useimmiten asiat hämmentyvät, kun mukana on ulkomaisia ​​merkkejä.

Tässä on ratkaisuni. Se tasoittaa GET/POST/REQUEST (jätin evästeet pois, mutta voit lisätä ne tarvittaessa) jokaisella sivulatauksella ennen käsittelyä. Se toimii hyvin otsikossa. PHP antaa varoituksia, jos se ei pysty automaattisesti määrittämään lähdekoodausta, joten nämä varoitukset estetään @-merkillä.

//Muunna kaikki muuttujamme UTF-8:ksi, jotta voit pelata mukavasti tietokannan kanssa... //Käytä tässä automaattista tunnistusta, jotta emme koodaa kaksoiskoodausta... //Poista mahdolliset varoitukset @:lla, jos koodausta ei voida havaita try ( $prosessi = array(&$_GET, &$_POST, &$_REQUEST); while (list($key, $val) = every($process)) ( foreach ($val as $k => $v) ( unset($process[$key][$k]); if (is_array($v)) ( $process[$key][@mb_convert_encoding($k,"UTF-8","auto")] = $ v $prosessi = &$prosessi[$avain][@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(poikkeus $ex)()

Olen katsastanut koodausratkaisuja AGESilla ja tämä sivu on todennäköisesti vuosien etsinnän loppu! Tarkistin joitain mainitsemistasi ehdotuksista, ja tässä on huomautukseni:

Tämä on testilinjani:

tämä on rivi "wròng wrìtten", jota en käyttänyt erityisesti chàrsin määrittämiseen nähdäkseni ne, muuntanut fùnctìon!! Joten mitä tämä on!

Sivuni fontti on UTF-8

Jos teen INSERTin tällä tavalla, DB:ssäni on joitain merkkejä, jotka ovat todennäköisesti peräisin Marsista... joten minun on muutettava ne "järkeväksi" UTF-8:ksi. Yritin utf8_encode():ta, mutta vieraita merkkejä tunkeutuivat edelleen tietokantaan...

Joten yritin käyttää forceUTF8-funktiota, joka sijaitsee numerossa 8, mutta DB:ssä tallennettu merkkijono näyttää tältä:

tämä on "wròng wrìtten"-merkkijono, mutta minä en halunnut pù "sòme"-erityischà rs nähdä thèm, convertèd by fùnctìon!! Joten mikä tämä on!

Joten keräämällä lisää tietoa tälle sivulle ja yhdistämällä ne muiden sivujen muihin tietoihin, ratkaisin ongelman tällä ratkaisulla:

$finallyIDidIt = mb_convert_encoding($merkkijono, mysql_client_encoding($resurssitunnus), mb_detect_encoding($merkkijono));

Nyt tietokannassani on merkkijono oikealla koodauksella.

Huomautus: Vain huomautus huolehtia mysql_client_encoding-toiminnosta! Sinun on oltava yhteydessä tietokantaan, koska tämä toiminto vaatii parametrina resurssitunnuksen.

Mutta ok, teen vain tämän uudelleenkoodauksen ennen INSERTiä, joten se ei ole minulle ongelma.

Toivottavasti tästä on apua, joku tämän sivun kaltainen henkilö auttoi minua!

Kiitos kaikille!

Mielenkiintoinen asia mb_detect_encodingissa ja mb_convert_encodingissa on se, että tarjoamiesi koodausten järjestyksellä on merkitystä:

// $syöttö on itse asiassa UTF-8 mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8"); // ISO-8859-9 (VÄÄRIN!) mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9"); // UTF-8 (OK)

Tällä tavalla voit käyttää tiettyä järjestystä määritettäessä odotettuja koodauksia. Muista kuitenkin, että tämä ei ole idioottivarma.

Echo mb_detect_encoding($str, "auto");

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

En oikein tiedä, mitkä ovat tulokset, mutta ehdotan, että otat vain joitain kanaviasi eri koodauksilla ja kokeilet, toimiiko mb_detect_encoding vai ei.

Päivittää
auto on lyhenne sanoista "ASCII, JIS, UTF-8, EUC-JP, SJIS". se palauttaa havaitun koodauksen, jonka avulla voit muuntaa merkkijonon utf-8:ksi käyttämällä iconv .

En ole testannut, joten ei takuuta. ja ehkä on helpompikin tapa.

Tämä versio on saksan kielelle, mutta voit muokata $CHARSETS ja $TESTCHARS

Class CharsetDetector ( yksityinen staattinen $CHARSETS = array("ISO_8859-1", "ISO_8859-15", "CP850"); yksityinen staattinen $TESTCHARS = array("€", "ä", "Ä", "ö", "Ö", "ü", "Ü", "ß" julkinen staattinen funktio convert($string) ( return self::__iconv($string, self::getCharset($string)); ) julkinen staattinen funktio getCharset); ($string) ( $normalisoitu = self::__normalize($string); if(!strlen($normalized))return "UTF-8"; $best = "UTF-8"; $charcountbest = 0; foreach (self ::$CHARSETS kuin $merkkiset ;< $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 $text."
"; ) return $best; ) yksityinen staattinen funktio __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) $tavua = 4; elseif ($c > 223) $tavua = 3; elseif ($ c > 191) $ret .=$str[$i], jos (($i + $tavua) > $len) $ret .=$str[$i]; while ($tavua > 1) ( $i++; $b = ord($str[$i]); if ($b< 128 || $b >191) ($ret .=$ret2; $ret2=""; $i+=$bytes-1;$bytes=1; break;) else $ret2.=$str[$i]; $tavua--; ) ) ) palauttaa $ret; ) yksityinen staattinen funktio __iconv($merkkijono, $merkkisarja) (palauta iconv ($merkkisarja, "UTF-8" , $merkkijono); ) )

Kun olet lajitellut php-skriptit, älä unohda kertoa mysqlille, mitä koodausta siirrät ja haluat vastaanottaa sen.

Esimerkki: merkistöksi asetetaan utf8

Utf8-tietojen välittäminen latin1-taulukkoon latin1-I/O-istunnossa antaa nämä ikävät linnut. Näen tämän joka päivä vähittäiskaupoissa. Edestakaisin voi tuntua oikealta. Mutta phpmyadmin näyttää totuuden. Jos kerrot mysqlille, minkä koodauksen hyväksyt, se käsittelee mysql-tiedot puolestasi.

Olemassa olevien mysql-salattujen tietojen palauttaminen on toinen keskustelunaihe :)