php comment connaître le mappage d'encodage. Détermination de l'encodage de texte PHP - Un aperçu des solutions existantes plus un autre vélo. Des mots à la pratique

Je lis beaucoup de textes à partir de différents flux RSS et je les insère dans ma base de données.

Bien sûr, il existe plusieurs codages de caractères différents utilisés dans les canaux, par ex. UTF-8 et ISO-8859-1.

Malheureusement, il y a parfois des problèmes avec les encodages de texte. Exemple:

1) "ß" dans "Fußball" devrait ressembler à ceci dans ma base de données : "Ÿ". Si c'est "Ÿ", il s'affiche correctement.

2) Parfois, le "ß" dans "Fußball" ressemble à ceci dans ma base de données : "ß". Ensuite, il est affiché de manière incorrecte, bien sûr.

3) Dans d'autres cas, "ß" est stocké en tant que "ß" - donc sans aucun changement. Ensuite, il s'affiche également de manière incorrecte.

Que puis-je faire pour éviter les cas 2 et 3 ?

Comment puis-je faire en sorte que tout soit le même encodage, de préférence UTF-8 ? Quand dois-je utiliser utf8_encode(), quand dois-je utiliser utf8_decode() (l'effet est clair, mais quand dois-je utiliser des fonctions ?) et quand dois-je faire quoi que ce soit avec l'entrée ?

Pouvez-vous m'aider et me dire comment faire tout le même codage ? Peut-être avec la fonction mb-detect-encoding() ? Puis-je écrire une fonction pour cela? Donc mes problèmes sont: 1) Comment savoir quel encodage est utilisé dans le texte 2) Comment le convertir en UTF-8 - quel que soit l'ancien encodage

ÉDITER: Une telle fonction fonctionnerait-elle ?

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

J'ai testé mais ça ne marche pas. Quel est le problème avec lui?

24 réponses

Si vous appliquez utf8_encode() à une chaîne UTF8 déjà existante, elle renverra une sortie UTF8 mutilée.

J'ai créé une fonction qui corrige tous ces problèmes. Il s'appelle Encoding::toUTF8().

Vous n'avez pas besoin de savoir quel est l'encodage de vos chaînes. Il peut s'agir de Latin1 (iso 8859-1), Windows-1252 ou UTF8, ou la chaîne peut les contenir. Encoding::toUTF8() convertira tout en UTF8.

Je l'ai fait parce que le service me donnait un flux de données, tout foiré, mélangeant UTF8 et Latin1 sur la même ligne.

Usage:

Require_once("Encoding.php"); utilisez \ForceUTF8\Encoding ; // Il est maintenant dans l'espace de noms. $utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string); $latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);

J'ai inclus une autre fonction, Encoding::fixUFT8(), qui corrigera chaque chaîne UTF8 qui semble mal formée.

Usage:

Require_once("Encoding.php"); utilisez \ForceUTF8\Encoding ; // Il est maintenant dans l'espace de noms. $utf8_string = Encodage ::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

Mise à jour : j'ai converti la fonction (forceUTF8) en une famille de fonctions statiques dans la classe Encoding. Nouvelle fonctionnalité- Encodage ::toUTF8().

Vous devez d'abord déterminer quel encodage a été utilisé. Étant donné que vous analysez des flux RSS (peut-être via HTTP), vous devez lire l'encodage à partir du paramètre charset du champ Content-Type de l'en-tête HTTP. S'il est manquant, lisez l'encodage à partir de l'attribut d'encodage de l'instruction de traitement. Si cela manque également, utilisez UTF-8 tel que défini dans la spécification.

Changer Voici ce que je vais probablement faire :

La détection d'encodage est difficile.

mb_detect_encoding fonctionne en devinant parmi plusieurs candidats que vous passez. Dans certains encodages, certaines séquences d'octets ne sont pas valides, il peut donc faire la distinction entre différents candidats. Malheureusement, il existe de nombreux encodages où les mêmes octets sont valides (mais différents). Dans ces cas, il n'est pas possible de déterminer le codage ; Vous pouvez implémenter votre propre logique pour faire des suppositions dans ces cas. Par exemple, les données provenant d'un site japonais sont susceptibles d'être encodées en japonais.

Alors que vous ne traitez que des langues d'Europe occidentale, considérez les trois principaux encodages : utf-8 , iso-8859-1 et cp-1252 . Parce qu'ils sont les valeurs par défaut pour de nombreuses plates-formes, ils sont également susceptibles d'être mal signalés. Par exemple. si les gens utilisent des encodages différents, ils seront probablement francs à ce sujet car sinon leur Logiciel cassera très souvent. C'est donc une bonne stratégie de faire confiance au fournisseur, à moins que l'encodage ne soit déclaré comme l'un de ces trois. Vous devez toujours doubler qu'il est vraiment valide en utilisant mb_check_encoding (notez que valide n'est pas la même chose qu'être - la même entrée peut être valide pour de nombreux encodages). Si c'est l'un d'entre eux, vous pouvez utiliser mb_detect_encoding pour les distinguer. Heureusement, c'est assez déterministe ; Il vous suffit d'utiliser la séquence de détection correcte, qui est UTF-8, ISO-8859-1, WINDOWS-1252 .

Une fois que vous avez trouvé l'encodage, vous devez le convertir en sa représentation interne (utf-8 est le seul choix raisonnable). La fonction utf8_encode convertit iso-8859-1 en utf-8 , elle ne peut donc être utilisée que pour ce type d'entrée particulier. Pour les autres encodages, utilisez mb_convert_encoding .

Cette feuille de triche répertorie certaines mises en garde courantes liées à la gestion de l'UTF-8 par PHP : http://developer.loftdigital.com/blog/php-utf-8-cheatsheet

Cette fonction, qui détecte les caractères multi-octets dans une chaîne, peut également être utile ():

Function detectUTF8($string) ( return preg_match("%(?: [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte |\xE0[\xA0-\xBF][\x80- \xBF] # excluant les overlongs |[\xE1-\xEC\xEE\xEF][\x80-\xBF](2) # 3 octets droits |\xED[\x80-\x9F][\x80-\xBF] # excluant les substituts |\xF0[\x90-\xBF][\x80-\xBF](2) # plans 1-3 |[\xF1-\xF3][\x80-\xBF](3) # plans 4- 15 |\xF4[\x80-\x8F][\x80-\xBF](2) # plan 16)+%xs", $string); )

Un petit avertissement, vous avez dit que "ß" devrait apparaître comme "Ÿ" dans votre base de données.

C'est probablement parce que vous utilisez une base de données avec un encodage de caractères latin1, ou peut-être que la connexion php-mysql est mal configurée, php pense que votre mysql est configuré pour utiliser utf-8, donc il envoie des données en utf8, mais votre mysql croit que php envoie des données encodé en iso-8859-1, il pourrait donc essayer d'encoder vos données envoyées en utf-8, causant à nouveau des problèmes comme celui-ci.

Jetez un oeil à ceci, cela pourrait vous aider: http://php.net/manual/en/function.mysql-set-charset.php

Vous devez vérifier l'encodage sur l'entrée car les réponses peuvent être encodées avec différents encodages.
Je force tout le contenu à être envoyé en UTF-8 en faisant la détection et la traduction en utilisant la fonction suivante :

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

Cette procédure transformera tout variables PHP, qui proviennent de l'hôte distant en UTF-8.
Ou ignorez la valeur si l'encodage ne peut pas être détecté ou converti.
Vous pouvez le personnaliser selon vos besoins.
Il suffit de l'appeler avant d'utiliser des variables.

Votre encodage semble être encodé en UTF-8 à deux reprises; c'est-à-dire d'un autre encodage, à UTF-8 et à nouveau à UTF-8. C'est comme si l'iso-8859-1 était converti d'iso-8859-1 en utf-8 et que la nouvelle ligne était traitée comme iso-8859-1 pour une autre conversion en UTF-8.

Voici un pseudo-code pour ce que vous avez fait :

$chaîne d'entrée = getFromUser(); $utf8string = iconv($current_encoding, "utf-8", $inputstring); $flawedstring = iconv($current_encoding, "utf-8", $utf8string);

Tu dois essayer:

  • détecter l'encodage avec mb_detect_encoding() ou tout ce que vous aimez utiliser
  • si UTF-8, convertir en iso-8859-1 et répéter l'étape 1
  • enfin reconvertir en UTF-8

Il suppose que vous avez utilisé iso-8859-1 dans la conversion "moyenne". Si vous avez utilisé Windows-1252, convertissez-le en Windows-1252 (latin1). L'encodage de la source d'origine n'est pas important ; celui que vous avez utilisé dans la deuxième conversion erronée.

C'est ma supposition quant à ce qui s'est passé; vous pourriez faire un peu plus pour obtenir quatre octets au lieu d'un octet ASCII étendu.

L'allemand utilise également iso-8859-2 et windows-1250 (latin2).

Le développement de l'encodage des caractères des flux RSS semble complexe. Même les pages Web normales omettent ou mentent souvent à propos de leur encodage.

Ainsi, vous pouvez essayer d'utiliser la méthode de détection d'encodage correcte, puis revenir à une forme de détection automatique (deviner).

Je sais que c'est une vieille question, mais je crois qu'une réponse utile ne fait jamais de mal. J'ai des problèmes avec mon encodage entre les applications de bureau, les variables SQLite et GET/POST. Certains d'entre eux seront en UTF-8, d'autres en ASCII, et fondamentalement, les choses deviendront confuses lorsque des caractères étrangers seront impliqués.

Voici ma solution. Il aplatit votre GET/POST/REQUEST (j'ai raté biscuits, mais vous pouvez les ajouter si nécessaire) à chaque chargement de page avant le traitement. Cela fonctionne bien dans l'en-tête. PHP émettra des avertissements s'il ne peut pas déterminer automatiquement l'encodage source, donc ces avertissements sont supprimés avec @.

//Convertissez tout dans nos vars en UTF-8 pour bien jouer avec la base de données... //Utilisez une détection automatique ici pour nous aider à ne pas encoder deux fois... //Supprimez les avertissements possibles avec @ lorsque l'encodage ne peut pas être détecté try ( $process = array(&$_GET, &$_POST, &$_REQUEST); while (list($key, $val) = each($process)) ( foreach ($val as $k => $v) ( unset($process[$key][$k]); if (is_array($v)) ( $process[$key][@mb_convert_encoding($k,"UTF-8","auto")] = $ v; $process = &$process[$key][@mb_convert_encoding($k,"UTF-8","auto")]; ) else ( $process[$key][@mb_convert_encoding($k,"UTF- 8","auto")] = @mb_convert_encoding($v,"UTF-8","auto"); ) ) ) unset($process); ) catch(Exception $ex)()

J'ai vérifié les solutions de codage avec AGES et cette page est probablement la fin d'années de recherche ! J'ai testé certaines des suggestions que vous avez mentionnées et voici mes notes :

Ceci est ma chaîne de test:

c'est la chaîne "wròng wrìtten" que je n'ai pas utilisée pour le réglage des caractères personnalisés pour les voir, convertis par fùnctìon !! Qu'est-ce que c'est!

La police de ma page est UTF-8

Si je fais l'INSERT de cette façon, j'ai des caractères dans ma base de données qui viennent probablement de Mars... donc je dois les convertir en UTF-8 "sain". J'ai essayé utf8_encode() mais des caractères extraterrestres envahissaient toujours ma base de données...

J'ai donc essayé d'utiliser la fonction forceUTF8 postée au numéro 8, mais dans la BD, la chaîne enregistrée ressemble à ceci :

c'est "wròng wrìtten" string mais j'ai besoin de pù "sòme" chà rs spéciaux pour les voir, convertis par fùnctìon!! Qu'est-ce que c'est!

Ainsi, en rassemblant plus d'informations sur cette page et en les combinant avec d'autres informations sur d'autres pages, j'ai résolu le problème avec cette solution :

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

Maintenant, dans ma base de données, j'ai une chaîne avec le bon encodage.

Noter: Seule note de prendre soin de la fonction mysql_client_encoding ! Vous devez être connecté à la base de données car cette fonction nécessite un identifiant de ressource en paramètre.

Mais ok, je fais juste ce recodage avant mon INSERT, donc ce n'est pas un problème pour moi.

J'espère que cela aide quelqu'un comme cette page m'a aidé!

Merci tout le monde!

La chose intéressante à propos de mb_detect_encoding et mb_convert_encoding est que l'ordre des encodages que vous suggérez est important :

// $input est en fait UTF-8 mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8"); // ISO-8859-9 (FAUX !) mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9"); // UTF-8 (OK)

Vous pouvez donc utiliser un ordre spécifique lors de la spécification des encodages attendus. Cependant, sachez que ce n'est pas fiable.

echo mb_detect_encoding($str, "auto");

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

Je ne sais pas vraiment quels sont les résultats, mais je vous suggère de prendre certains de vos flux avec différents encodages et d'essayer si mb_detect_encoding fonctionne ou non.

Mettre à jour
auto est l'abréviation de "ASCII, JIS, UTF-8, EUC-JP, SJIS". il renvoie l'encodage détecté, que vous pouvez utiliser pour convertir la chaîne en utf-8 avec iconv .

Je ne l'ai pas testé, donc aucune garantie. et peut-être qu'il y a un moyen plus simple.

Cette version est pour l'allemand, mais vous pouvez modifier $CHARSETS et $TESTCHARS

Classe CharsetDetector ( statique privée $CHARSETS = array("ISO_8859-1", "ISO_8859-15", "CP850"); statique privée $TESTCHARS = array("€", "ä", "Ä", "ö", "Ö", "ü", "Ü", "ß"); fonction statique publique convert($string) ( return self::__iconv($string, self::getCharset($string)); ) fonction statique publique getCharset ($string) ( $normalized = self::__normalize($string); if(!strlen($normalized))return "UTF-8"; $best = "UTF-8"; $charcountbest = 0; foreach (self ::$CHARSETS as $charset) ( $str = self::__iconv($normalized, $charset); $charcount = 0; $stop = mb_strlen($str, "UTF-8"); for($idx = 0 ;$idx< $stop; $idx++) { $char = mb_substr($str, $idx, 1, "UTF-8"); foreach (self::$TESTCHARS as $testchar) { if($char == $testchar) { $charcount++; break; } } } if($charcount>$charcountbest) ( $charcountbest=$charcount; $best=$charset; ) //echo $text."
"; ) renvoie $best; ) fonction statique privée __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) $bytes = 4; elseif ($c > 223) $bytes = 3; elseif ($ c > 191) $octets = 2 ; sinon $ret .=$str[$i] ; si (($i + $octets) > $len) $ret .=$str[$i] ; $ret2=$str [$i] ; tandis que ($octets > 1) ( $i++ ; $b = ord($str[$i]); si ($b< 128 || $b >191) ($ret .=$ret2; $ret2=""; $i+=$bytes-1;$bytes=1; break;) else $ret2.=$str[$i]; $octets-- ; ) ) ) return $ret; ) fonction statique privée __iconv($string, $charset) ( return iconv ($charset, "UTF-8" , $string); ) )

Après avoir trié vos scripts php, n'oubliez pas de dire à mysql quel encodage vous transmettez et souhaitez l'obtenir.

Exemple : définir le jeu de caractères sur utf8

Passer des données utf8 à la table latin1 dans la session d'E/S latin1 donne ces vilains birdies. Je vois ça tous les jours dans les magasins de détail. Les allers-retours peuvent sembler justes. Mais phpmyadmin montrera la vérité. Dire à mysql quel encodage vous transmettez gérera données mysql Pour vous.

Comment récupérer des données mysql brouillées existantes est une autre question à discuter. :)

Il y avait un problème : comment déterminer rapidement l'encodage d'une chaîne de texte par rapport à UTF-8 De plus en plus, vous devez travailler avec des chaînes en encodage UNICODE.

Vous trouverez ci-dessous une fonction permettant de vérifier si l'encodage UNICODE (UTF-8) doit être converti en encodage WINDOWS (win-1251)

La fonction donne une réponse assez précise, bien qu'elle ne repose pas sur une conversion code par caractère.

une fonction detect_my_utf($s)( $s=urlencode($s); // opération supplémentaire dans certains cas (commentez-la) $res="0"; $j=strlen($s); $s2=strtoupper($s ) ; $s2=str_replace("%D0","",$s2); $s2=str_replace("%D1","",$s2); $k=strlen($s2); $m=1; si ($k>0)( $m=$j/$k; si (($m>1.2)&&($m

En bref - description de la fonction detect_my_utf():

  • convertir (chaîne en format spécial)
  • calculer la longueur de la chaîne d'entrée
  • convertir toutes les lettres d'une chaîne en majuscules
  • supprimer les codes spécifiques %D0 et %D1
  • calculer la longueur de la nouvelle ligne
  • obtenir le rapport de l'ancienne ligne à la nouvelle

Si ce rapport est de 1 ou proche de celui-ci, il y a un soupçon que la chaîne entrante n'a pas été encodée en UNICODE. Si ce rapport est compris entre 1,2 et 2,2, vous pouvez réencoder en toute sécurité la chaîne dans le codage WINDOWS win-1251.

A la sortie de la fonction, nous avons 0 ou 1, respectivement, pas UNICODE ou UNICODE.

Exemples d'exécution de fonctions :

Chaîne d'entrée : R°R?RyoR?R°S+RyoRyo R? imageready Chaîne convertie : %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 Résultat de la fonction : 1 Phrase codée : comment créer une animation dans imageready

Chaîne d'entrée : R?C?R?R?R?C

Chaîne d'entrée :

Chaîne d'entrée : guide de dessin Chaîne convertie : %EF%EE%F1%EE%E1%E8%E5 %EF%EE %F0%E8%F1%EE%E2%E0%ED%E8%FE Résultat de la fonction : 0 Phrase codée : Tutoriel de dessin Cet algorithme fonctionne bien avec une variété de chaînes entrantes dans le cadre d'un service de statistiques de conversion de moteur de recherche.

Matériaux intéressants sur le site:

  • Un article sur l'intérêt de recherche du site. Peut-être que certains matériaux sont déjà obsolètes depuis 10 ans, mais certains points méritent qu'on s'y attarde.

  • Votre point de vue sur la problématique des échanges d'hyperliens entre le site donneur et les sites receveurs.

  • Un autre hack de la vie. Nous avons battu des joueurs malhonnêtes dans le jeu "Balda". Grande base de données de mots qui peut être facilement étendue.

Idée - Loterie

Je n'ai pas eu l'idée d'obtenir l'encodage, mais malheureusement, je ne peux pas non plus dire à l'auteur maintenant, car c'était il y a environ 4 ans et d'où j'ai obtenu cette information depuis longtemps. L'auteur a suggéré une variante de la définition et a montré un exemple pour 1-2 encodages sur Langage Python. La simplicité de sa solution ne m'a pas laissé de côté, et je l'ai développée jusqu'au résultat souhaité.
L'essence de l'idée réside dans les tables d'encodage elles-mêmes. Comme vous le savez, tout encodage contient sa propre table de codes et une valeur spécifique est attribuée à chaque caractère de l'encodage. Je ne montrerai pas ici les tables d'encodage, maintenant il est assez facile de les trouver sur Internet.
Le principe de mise en œuvre est le suivant :
  1. Une variable tableau est créée pour stocker le résultat de "l'analyse" du texte vérifié. Chaque élément du tableau contiendra le résultat pour un encodage particulier.
  2. Le texte reçu en entrée de la fonction est trié caractère par caractère.
  3. Un ordinal (la valeur de ce caractère) est extrait de chaque caractère et comparé à la plage d'encodage.
  4. Si la valeur tombe sur un caractère majuscule (majuscule), l'élément de tableau qui stocke le résultat de cet encodage est défini sur 1.
  5. Si la valeur tombe sur un caractère minuscule (petit), l'élément de tableau qui stocke le résultat de cet encodage est défini sur 3.
  6. Cet encodage, plus précisément, cet élément du tableau qui stocke le résultat de son encodage, qui a marqué le plus de points, est très probablement l'encodage d'origine.
Cet algorithme est valable pour les encodages à un octet tels que KOI-8, CP1251 (windows-1251) et autres. Cependant, pour les encodages à deux octets (dans mon cas UTF-8), cette approche donnera un résultat erroné. Pour commencer, j'ai essayé de résoudre ce problème en ajoutant 5 pour les caractères majuscules et 7 pour les caractères minuscules. Le résultat est devenu meilleur, mais il y avait encore des erreurs de reconnaissance. Après quelques expérimentations, j'ai conclu que pour la définition correcte de l'UTF, avec des caractères majuscules, il fallait ajouter 10 au résultat, pour les minuscules 14, soit 2 fois plus que mon hypothèse initiale. Cependant, pour une meilleure compréhension visuelle du code, j'ai laissé 5 et 7 pour les caractères UTF, respectivement, et déjà lors de la vérification, ces valeurs sont augmentées de 2 et ajoutées au résultat.
C'est essentiellement tout l'algorithme. Et sans aucun tracas supplémentaire.
La plupart du temps pour la mise en œuvre de cette fonction, bien sûr, a été consacré à la recherche de tables de codes et à la disposition correcte des plages. Non seulement il était assez difficile de trouver la table de codes réelle au moment où j'ai écrit cette fonction pour la première fois, mais aussi les plages de caractères qu'elles contiennent sautent au hasard. Cependant, j'ai ensuite opté pour les encodages les plus pertinents (à ce jour) : UTF-8, CP1251, KOI8-R, IBM866, ISO-8859-5 et MAC. Si ces encodages ne vous suffisent pas, vous pouvez compléter le code en vous basant sur cet algorithme.

Des mots à la pratique

En fait, tout le code de la fonction en Python ressemble à ceci :

Encodages = ( "UTF-8": "utf-8", "CP1251": "windows-1251", "KOI8-R": "koi8-r", "IBM866": "ibm866", "ISO-8859- 5": "iso-8859-5", "MAC": "mac", ) """ Définition de l'encodage de texte """ def get_codepage(str = None): majuscule = 1 minuscule = 3 utfupper = 5 utflower = 7 pages de code = () pour enc dans encodings.keys() : codepages = 0 si str n'est pas None et len(str) > 0 : last_simb = 0 pour simb dans str : simb_ord = ord(simb) """caractères non russes" "" si simb_ord< 128 or simb_ord >256 : continuer """UTF-8""" si last_simb == 208 et (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 = article retour idx
Exemple d'appel de fonction

Encodages d'impression

Qu'en est-il de PHP

Il n'a pas été difficile de réécrire une fonction toute faite de Python vers PHP. En apparence, il n'est pratiquement pas différent de son ancêtre en Python :

/** * Définir l'encodage du texte * @param String $text Text * @return String Encodage du texte */ function get_codepage($text = "") ( if (!empty($text)) ( $utflower = 7; $utfupper = 5 ; $lowercase = 3 ; $uppercase = 1 ; $last_simb = 0 ; $charsets = array("UTF-8" => 0, "CP1251" => 0, "KOI8-R" => 0, "IBM866" => 0, "ISO-8859-5" => 0, "MAC" => 0,); pour ($a = 0; $a< strlen($text); $a++) { $char = ord($text[$a]); // non-russian characters if ($char<128 || $char>256) continuer ; // UTF-8 si (($last_simb==208) && (($char>143 && $char<176) || $char==129)) $charsets["UTF-8"] += ($utfupper * 2); if ((($last_simb==208) && (($char>175 && $car<192) || $char==145)) || ($last_simb==209 && $char>127 && $car<144)) $charsets["UTF-8"] += ($utflower * 2); // CP1251 if (($char>223 && $car<256) || $char==184) $charsets["CP1251"] += $lowercase; if (($char>191 && $car<224) || $char==168) $charsets["CP1251"] += $uppercase; // KOI8-R if (($char>191 && $car<224) || $char==163) $charsets["KOI8-R"] += $lowercase; if (($char>222 && $car<256) || $char==179) $charsets["KOI8-R"] += $uppercase; // IBM866 if (($char>159 && $car<176) || ($char>223 && $car<241)) $charsets["IBM866"] += $lowercase; if (($char>127 && $car<160) || $char==241) $charsets["IBM866"] += $uppercase; // ISO-8859-5 if (($char>207 && $car<240) || $char==161) $charsets["ISO-8859-5"] += $lowercase; if (($char>175 && $car<208) || $char==241) $charsets["ISO-8859-5"] += $uppercase; // MAC if ($char>221 && $car<255) $charsets["MAC"] += $lowercase; if ($char>127 && $car<160) $charsets["MAC"] += $uppercase; $last_simb = $char; } arsort($charsets); return key($charsets); } }
Exemple d'appel de fonction

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

Likbez, ou Ne pas interférer avec la machine pour travailler

Vous ne devriez pas essayer de crash-tester cette fonction. Il ressort clairement de l'algorithme que moins il reçoit de texte en entrée, plus il est probable que la fonction reconnaîtra l'encodage de manière incorrecte. D'un autre côté, alimenter les volumes de Léon Tolstoï n'a pas non plus de sens : cette méthode fait un excellent travail avec une petite phrase de 100-200 caractères. Et bien que dans les exemples d'appel à l'entrée j'ai envoyé tout le contenu d'un certain fichier "test.txt", dans lequel on supposait qu'il y avait du texte dont l'encodage devait être déterminé, un petit morceau de texte peut (et devrait) être passé à l'entrée de la fonction.
Les perversions avec des lettres majuscules et minuscules mixtes ne sont généralement pas appropriées dans ce cas, car cette méthode a été écrite pour une tâche ordinaire ordinaire avec un russe approximativement alphabétisé. Et de telles expériences me rappellent le plus souvent une blague:

Une usine de menuiserie russe a acheté une machine japonaise. Des ouvriers russes se sont rassemblés autour de lui et découvrons comment il travaille. On a pris la planche, on l'a mise dedans. Unité : zzzzzzzzzzzzzzzzin... A la sortie, un tabouret tout fait. Les gars : Rien à soi !!! L'unité sur l'écran : eh bien, qu'en avez-vous pensé ? Un autre a pris une bûche non taillée et l'a insérée dans l'appareil. Unité : zzzzzzzzzzzzzz... A la sortie, un buffet sculpté est prêt. Les gars : Rien à soi !!! L'unité sur l'écran : eh bien, qu'en avez-vous pensé ? Le troisième homme ne pouvait pas le supporter, a tiré le rail de quelque part et l'a enfoncé dans l'unité. L'unité : drrrrr-tyh-tyh-tyh... Ça fumait et l'inscription sur l'afficheur : Rien à soi !!! Guys : Eh bien, qu'en avez-vous pensé ?
Donc, pour de tels tests pervers, vous aurez très probablement besoin d'un algorithme pervers, ce que cette fonction n'est pas. Et de pratique je dirai que lors de l'utilisation pendant 4 ans, cette méthode ne m'a jamais fait défaut et a toujours donné le bon résultat.
J'espère que mon article sera utile à quelqu'un.
Merci pour votre attention.

Lorsque vous utilisez tout ou partie du contenu, n'oubliez pas de faire un lien vers la source, c'est-à-dire vers mon blog.

Face à la tâche - détection automatique de la page/du texte/de n'importe quel encodage. La tâche n'est pas nouvelle et de nombreux vélos ont déjà été inventés. L'article contient un petit aperçu de ce qui a été trouvé sur le net - plus une offre de ma part, me semble-t-il, une solution valable.

1. Pourquoi pas mb_detect_encoding() ?

Bref, ça ne marche pas.

Regardons:
// A l'entrée - texte russe encodé en CP1251 $string = iconv("UTF-8", "Windows-1251", "Il s'approcha d'Anna Pavlovna, lui baisa la main, lui offrant sa tête chauve parfumée et brillante, et s'assit calmement sur le canapé."); // Voyons ce que md_detect_encoding() nous donne. Premier $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"))); // FAUX 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 // Maintenant $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)); // FAUX 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
Comme vous pouvez le voir, la sortie est un gâchis complet. Que fait-on quand on ne comprend pas pourquoi une fonction se comporte ainsi ? C'est vrai, nous google. Trouvé une excellente réponse.

Pour enfin dissiper tous les espoirs d'utilisation de mb_detect_encoding(), vous devez entrer dans les sources de l'extension mbstring. Alors retroussez vos manches, c'est parti :
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // ligne 2703 ret = mbfl_identify_encoding_name(&string, elist, size, strict); ...
Ctrl+clic :
// 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; encoding = mbfl_identify_encoding(string, elist, elistsz , strict); ...
Ctrl+clic :
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * identifier l'encodage */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict) ( ...
Je ne posterai pas le texte intégral de la méthode, afin de ne pas encombrer l'article avec des sources inutiles. Ceux qui sont intéressés verront par eux-mêmes. Nous nous intéresserons à la ligne numéro 593, où la vérification est effectivement faite si le caractère correspond à l'encodage :
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, filter); if (filter->flag) ( bad++; )
Voici les principaux filtres pour le cyrillique à un octet :

Windows-1251 (commentaires d'origine conservés)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* tout cela est si moche maintenant ! */ static int mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c< 0xff) filter->drapeau = 0 ; sinon filtre->

KOI8-R
// ext/mbstring/libmbfl/filters/mbfilter_koi8r.c:142 static int mbfl_filt_ident_koi8r(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c< 0xff) filter->drapeau = 0 ; sinon filtre->flag = 1 ; /* pas ça */ return c; )

ISO-8859-5 (tout est généralement amusant ici)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *filter) ( return c; )
Comme vous pouvez le voir, ISO-8859-5 renvoie toujours TRUE (pour renvoyer FALSE, vous devez définir filter->flag = 1).

Lorsque nous avons regardé les filtres, tout s'est mis en place. CP1251 est indiscernable de KOI8-R. ISO-8859-5 en général, s'il est dans la liste des encodages, il sera toujours détecté comme correct.

En général, échouer. C'est compréhensible - uniquement par les codes de caractères, il est impossible dans le cas général de connaître le codage, car ces codes se croisent dans différents codages.

2. Ce que Google donne

Et Google donne toutes sortes de misère. Je ne posterai même pas la source ici, voyez par vous-même si vous le souhaitez (enlevez l'espace après http://, je ne sais pas comment afficher le texte pas sous forme de lien):

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

3. Recherche habituelle

1) à nouveau les codes de caractères :

2) à mon avis, une solution très intéressante :
Avantages et inconvénients dans les commentaires sur le lien. Personnellement, je pense que cette solution n'est redondante que pour la détection d'encodage - elle s'avère trop puissante. La définition de l'encodage en elle - comme effet secondaire).

4. En fait, ma décision

L'idée est née lors de la visualisation du deuxième lien de la section précédente. L'idée est la suivante : on prend un grand texte russe, on mesure les fréquences des différentes lettres, et on utilise ces fréquences pour détecter l'encodage. Pour l'avenir, je dirai tout de suite qu'il y aura des problèmes avec les grandes et les petites lettres. Par conséquent, je poste des exemples de fréquences de lettres (appelons-le "spectre") à la fois sensibles à la casse et sans (dans le second cas, j'ai ajouté une lettre encore plus grande à la lettre minuscule avec la même fréquence, et supprimé toutes les grandes) . Dans ces "spectres", toutes les lettres avec des fréquences inférieures à 0,001 et un espace sont découpées. Voici ce que j'ai obtenu après avoir traité "Guerre et paix":

"Spectre" sensible à la casse :
tableau ("O" => 0.095249209893009, "E" => 0.06836817536026, "A" => 0.067481298384992, "u" => 0.0522427944063325, .... "02." => 0.0021318391371162, " П "=> 0.0018574762967903," F "=> 0.0015961610948418," in "=> 0.0014044332975731," O "=> 0.0013188987793209," k "=> 0.0011804488387602," m "=> 0.001061932790165,)

Insensible à la casse :
Array ("O" => 0.095249209893009, "O" => 0.095249209893009, "E" => 0.06836817536026, "A" => 0.067481298384992, "A" 0.067481298384992, " , "Et" => 0.055995027400041, .... "C" => 0.0029893589260344, "C" => 0.0029893589260344, "щ" => 0.0024649163501406, "e" => 0.0022528922266507, "E" => 0.002252892226507, "Ф" => 0.0015961610948418, "Ф" => 0.0015961610948418,)

Spectres dans différents encodages (clés de tableau - codes des caractères correspondants dans l'encodage correspondant) :

Davantage. On prend le texte d'un encodage inconnu, pour chaque encodage que l'on vérifie, on trouve la fréquence du caractère courant et on ajoute cet encodage au "rating". L'encodage avec la note la plus élevée est très probablement l'encodage de texte.

$encodings = array("cp1251" => require "specter_cp1251.php", "koi8r" => require "specter_koi8r.php", "iso88595" => require "specter_iso88595.php"); $enc_rates = array(); pour ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ( $enc_rates[$encoding] += $char_specter)] ; ) var_dump($enc_rates);
N'essayez même pas d'exécuter ce code par vous-même - cela ne fonctionnera pas. Vous pouvez considérer cela comme un pseudocode - j'ai omis les détails afin de ne pas encombrer l'article. $char_specter est juste les tableaux référencés dans pastebin.

résultats
Les lignes du tableau sont l'encodage du texte, les colonnes sont le contenu du tableau $enc_rates.

1) $str = "Texte russe" ;
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

Tout va bien. Le vrai encodage a déjà une note 4 fois plus élevée que le reste - c'est sur un texte aussi court. Pour plus textes longs le rapport sera à peu près le même.


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

Oups ! Bouillie complète. Mais parce que majuscules dans CP1251 correspondent généralement aux petits dans KOI8-R. Et les petites lettres sont utilisées à leur tour beaucoup plus souvent que les grandes. Nous définissons donc la chaîne de majuscules dans CP1251 comme KOI8-R.
Essayer de le faire insensible à la casse ("spectra" insensible à la casse)

1) $str = "Texte russe" ;
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 = "CHAINE CAPSOM TEXTE RUSSE" ;
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

Comme vous pouvez le voir, le codage correct conduit de manière stable avec des « spectres » sensibles à la casse (si la chaîne contient une petite quantité de majuscules) et insensible à la casse. Dans le second cas, avec ceux qui ne sont pas sensibles à la casse, le leader n'est pas si confiant, bien sûr, mais assez stable même sur de petites cordes. Vous pouvez également jouer avec les poids des lettres - les rendre non linéaires par rapport à la fréquence, par exemple.

5. Conclusion

Le sujet ne couvre pas le travail avec UTF-8 - il n'y a pas de différence fondamentale ici, sauf que l'obtention des codes de caractères et la division de la chaîne en caractères seront un peu plus longues/plus compliquées.
Ces idées peuvent être étendues non seulement aux encodages cyrilliques, bien sûr - la question n'est que dans le "spectre" des langues/encodages correspondants.

PS Si c'est très nécessaire/intéressant, alors je posterai la deuxième partie d'une bibliothèque entièrement fonctionnelle sur GitHub. Bien que je pense que les données contenues dans le message sont tout à fait suffisantes pour écrire rapidement une telle bibliothèque et répondre à vos propres besoins - le "spectre" de la langue russe est défini, il peut être facilement transféré à tous les encodages nécessaires.

Face à la tâche - détection automatique de la page/du texte/de n'importe quel encodage. La tâche n'est pas nouvelle et de nombreux vélos ont déjà été inventés. L'article contient un petit aperçu de ce qui a été trouvé sur le net - plus une offre de ma part, me semble-t-il, une solution valable.

1. Pourquoi pas mb_detect_encoding() ?

Bref, ça ne marche pas.

Regardons:
// A l'entrée - texte russe encodé en CP1251 $string = iconv("UTF-8", "Windows-1251", "Il s'approcha d'Anna Pavlovna, lui baisa la main, lui offrant sa tête chauve parfumée et brillante, et s'assit calmement sur le canapé."); // Voyons ce que md_detect_encoding() nous donne. Premier $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"))); // FAUX 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 // Maintenant $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)); // FAUX 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
Comme vous pouvez le voir, la sortie est un gâchis complet. Que fait-on quand on ne comprend pas pourquoi une fonction se comporte ainsi ? C'est vrai, nous google. Trouvé une excellente réponse.

Pour enfin dissiper tous les espoirs d'utilisation de mb_detect_encoding(), vous devez entrer dans les sources de l'extension mbstring. Alors retroussez vos manches, c'est parti :
// ext/mbstring/mbstring.c:2629 PHP_FUNCTION(mb_detect_encoding) ( ... // ligne 2703 ret = mbfl_identify_encoding_name(&string, elist, size, strict); ...
Ctrl+clic :
// 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; encoding = mbfl_identify_encoding(string, elist, elistsz , strict); ...
Ctrl+clic :
// ext/mbstring/libmbfl/mbfl/mbfilter.c:557 /* * identifier l'encodage */ const mbfl_encoding * mbfl_identify_encoding(mbfl_string *string, enum mbfl_no_encoding *elist, int elistsz, int strict) ( ...
Je ne posterai pas le texte intégral de la méthode, afin de ne pas encombrer l'article avec des sources inutiles. Ceux qui sont intéressés verront par eux-mêmes. Nous nous intéresserons à la ligne numéro 593, où la vérification est effectivement faite si le caractère correspond à l'encodage :
// ext/mbstring/libmbfl/mbfl/mbfilter.c:593 (*filter->filter_function)(*p, filter); if (filter->flag) ( bad++; )
Voici les principaux filtres pour le cyrillique à un octet :

Windows-1251 (commentaires d'origine conservés)
// ext/mbstring/libmbfl/filters/mbfilter_cp1251.c:142 /* tout cela est si moche maintenant ! */ static int mbfl_filt_ident_cp1251(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c< 0xff) filter->drapeau = 0 ; sinon filtre->

KOI8-R
// ext/mbstring/libmbfl/filters/mbfilter_koi8r.c:142 static int mbfl_filt_ident_koi8r(int c, mbfl_identify_filter *filter) ( if (c >= 0x80 && c< 0xff) filter->drapeau = 0 ; sinon filtre->flag = 1 ; /* pas ça */ return c; )

ISO-8859-5 (tout est généralement amusant ici)
// ext/mbstring/libmbfl/mbfl/mbfl_ident.c:248 int mbfl_filt_ident_true(int c, mbfl_identify_filter *filter) ( return c; )
Comme vous pouvez le voir, ISO-8859-5 renvoie toujours TRUE (pour renvoyer FALSE, vous devez définir filter->flag = 1).

Lorsque nous avons regardé les filtres, tout s'est mis en place. CP1251 est indiscernable de KOI8-R. ISO-8859-5 en général, s'il est dans la liste des encodages, il sera toujours détecté comme correct.

En général, échouer. C'est compréhensible - uniquement par les codes de caractères, il est impossible dans le cas général de connaître le codage, car ces codes se croisent dans différents codages.

2. Ce que Google donne

Et Google donne toutes sortes de misère. Je ne posterai même pas la source ici, voyez par vous-même si vous le souhaitez (enlevez l'espace après http://, je ne sais pas comment afficher le texte pas sous forme de lien):

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

3. Recherche habituelle

1) à nouveau les codes de caractères : habrahabr.ru/blogs/php/27378/#comment_710532

2) à mon avis, une solution très intéressante : habrahabr.ru/blogs/php/27378/#comment_1399654
Avantages et inconvénients dans les commentaires sur le lien. Personnellement, je pense que cette solution n'est redondante que pour la détection d'encodage - elle s'avère trop puissante. La définition de l'encodage en elle - comme effet secondaire).

4. En fait, ma décision

L'idée est née lors de la visualisation du deuxième lien de la section précédente. L'idée est la suivante : on prend un grand texte russe, on mesure les fréquences des différentes lettres, et on utilise ces fréquences pour détecter l'encodage. Pour l'avenir, je dirai tout de suite qu'il y aura des problèmes avec les grandes et les petites lettres. Par conséquent, je poste des exemples de fréquences de lettres (appelons-le "spectre") à la fois sensibles à la casse et sans (dans le second cas, j'ai ajouté une lettre encore plus grande à la lettre minuscule avec la même fréquence, et supprimé toutes les grandes) . Dans ces "spectres", toutes les lettres avec des fréquences inférieures à 0,001 et un espace sont découpées. Voici ce que j'ai obtenu après avoir traité "Guerre et paix":

"Spectre" sensible à la casse :
tableau ("O" => 0.095249209893009, "E" => 0.06836817536026, "A" => 0.067481298384992, "u" => 0.0522427944063325, .... "02." => 0.0021318391371162, " П "=> 0.0018574762967903," F "=> 0.0015961610948418," in "=> 0.0014044332975731," O "=> 0.0013188987793209," k "=> 0.0011804488387602," m "=> 0.001061932790165,)

Insensible à la casse :
Array ("O" => 0.095249209893009, "O" => 0.095249209893009, "E" => 0.06836817536026, "A" => 0.067481298384992, "A" 0.067481298384992, " , "Et" => 0.055995027400041, .... "C" => 0.0029893589260344, "C" => 0.0029893589260344, "щ" => 0.0024649163501406, "e" => 0.0022528922266507, "E" => 0.002252892226507, "Ф" => 0.0015961610948418, "Ф" => 0.0015961610948418,)

Spectres dans différents encodages (clés de tableau - codes des caractères correspondants dans l'encodage correspondant) :

Davantage. On prend le texte d'un encodage inconnu, pour chaque encodage que l'on vérifie, on trouve la fréquence du caractère courant et on ajoute cet encodage au "rating". L'encodage avec la note la plus élevée est très probablement l'encodage de texte.

$encodings = array("cp1251" => require "specter_cp1251.php", "koi8r" => require "specter_koi8r.php", "iso88595" => require "specter_iso88595.php"); $enc_rates = array(); pour ($i = 0; $i< len($str); ++$i) { foreach ($encodings as $encoding =>$char_specter) ( $enc_rates[$encoding] += $char_specter)] ; ) var_dump($enc_rates);
N'essayez même pas d'exécuter ce code par vous-même - cela ne fonctionnera pas. Vous pouvez considérer cela comme un pseudocode - j'ai omis les détails afin de ne pas encombrer l'article. $char_specter est juste les tableaux référencés dans pastebin.

résultats
Les lignes du tableau sont l'encodage du texte, les colonnes sont le contenu du tableau $enc_rates.

1) $str = "Texte russe" ;
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

Tout va bien. Le vrai encodage a déjà une note 4 fois plus élevée que le reste - c'est sur un texte aussi court. Pour les textes plus longs, le ratio sera à peu près le même.


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

Oups ! Bouillie complète. Parce que les grandes lettres de CP1251 correspondent généralement aux petites lettres de KOI8-R. Et les petites lettres sont utilisées à leur tour beaucoup plus souvent que les grandes. Nous définissons donc la chaîne de majuscules dans CP1251 comme KOI8-R.
Essayer de le faire insensible à la casse ("spectra" insensible à la casse)

1) $str = "Texte russe" ;
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 = "CHAINE CAPSOM TEXTE RUSSE" ;
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

Comme vous pouvez le voir, le codage correct conduit systématiquement à la fois avec des « spectres » sensibles à la casse (si la chaîne contient un petit nombre de lettres majuscules) et avec ceux qui ne sont pas sensibles à la casse. Dans le second cas, avec ceux qui ne sont pas sensibles à la casse, le leader n'est pas si confiant, bien sûr, mais assez stable même sur de petites cordes. Vous pouvez également jouer avec les poids des lettres - les rendre non linéaires par rapport à la fréquence, par exemple.

5. Conclusion

Le sujet ne couvre pas le travail avec UTF-8 - il n'y a pas de différence fondamentale ici, sauf que l'obtention des codes de caractères et la division de la chaîne en caractères seront un peu plus longues/plus compliquées.
Ces idées peuvent être étendues non seulement aux encodages cyrilliques, bien sûr - la question n'est que dans le "spectre" des langues/encodages correspondants.

PS Si c'est très nécessaire/intéressant, alors je posterai la deuxième partie d'une bibliothèque entièrement fonctionnelle sur GitHub. Bien que je pense que les données contenues dans le message sont tout à fait suffisantes pour écrire rapidement une telle bibliothèque et répondre à vos propres besoins - le "spectre" de la langue russe est défini, il peut être facilement transféré à tous les encodages nécessaires.

2022 wisemotors.com. Comment ça fonctionne. Fer. Exploitation minière. Crypto-monnaie.