code page exotique recherche ses jeunes...

ViPHP
ViPHP | 1380 Messages

17 juil. 2007, 10:51

Bonjour à la communauté!

Depuis plus de 5 ans j'importe un fichier plat généré par un application sur laquelle je n'ai aucun contrôle. J'ai cherché au début de déterminer quel codepage était utilisé pour ce fichier. Aucune ne semblait correspondre. Je me suis donc résolu a faire un strtr() sur l'ensemble des caractères sur une base empirique. Je suis parti de la codepage CP850 qui semblait s'en rapprocher le plus et par essai erreur j'ai pu constituer une table de remplacement qui marche (voir plus loin pour référence) . Mais c'est d'un lourd! A chaque import quotidien, ça rame à mort (gros fichier). De plus à chaque nouveau caractère non mappé, je dois m'y remettre.

J'ai essayé toutes les tables connues par iconv de linux. Toutes celles de ce site http://www.eki.ee/letter/ et plein d'autres choses encore.

Quand je pose la question à la société qui a développé l'application qui exporte le fichier plat, ils n'en savent rien et m'ont même demandé ce qu'était qu'une codepage. Bref, ça commence à m'énerver.

Par exemple, pour le caractère @, ils exportent un hex 86. Il me faudrait un site qui propose un "reverse lookup" avec en entrée le caractère et son code hex.

Une piste, un signe dans le ciel ou le marc de café?

Pour référence, mon mapping actuel vers ISO 8859-1:
$array_cp850 = array(

  "\x80"=>"\xC7", "\x81"=>"\xFC", "\x82"=>"\xE9", "\x83"=>"\xE2", "\x84"=>"\xE4", "\x85"=>"\xE0", "\x86"=>"\xE5",
  "\x87"=>"\xE7", "\x88"=>"\xEA", "\x89"=>"\xEB", "\x90"=>"\xC9", "\x91"=>"\xE6", "\x92"=>"\xC6", "\x93"=>"\xF4",
  "\x94"=>"\xF6", "\x95"=>"\xF2", "\x96"=>"\xFB", "\x97"=>"\xF9", "\x98"=>"\xFF", "\x99"=>"\xD6", "\x8A"=>"\xE8",
  "\x8B"=>"\xEF", "\x8C"=>"\xEE", "\x8D"=>"\xEC", "\x8E"=>"\xC4", "\x8F"=>"\xC5", "\x9A"=>"\xDC", "\x9B"=>"\xF8",
  "\x9C"=>"\xA3", "\x9D"=>"\xD8", "\x9E"=>"\xD7", "\x9F"=>"\xA0", "\xA0"=>"\xE1", "\xA1"=>"\xED", "\xA2"=>"\xF3",
  "\xA3"=>"\xFA", "\xA4"=>"\xF1", "\xA5"=>"\xD1", "\xA6"=>"\xAA", "\xA7"=>"\xBA", "\xA8"=>"\xBF", "\xA9"=>"\xAE",
  "\xAA"=>"\xAC", "\xAB"=>"\xBD", "\xAC"=>"\xBC", "\xAD"=>"\xA1", "\xAE"=>"\xAB", "\xAF"=>"\xBB", "\xB0"=>"\xA0",
  "\xB1"=>"\xA0", "\xB2"=>"\xA0", "\xB3"=>"\xA0", "\xB4"=>"\xA0", "\xB5"=>"\xC1", "\xB6"=>"\xC2", "\xB7"=>"\xC0",
  "\xB8"=>"\xA9", "\xB9"=>"\xA0", "\xBA"=>"\xA0", "\xBB"=>"\xA0", "\xBC"=>"\xA0", "\xBD"=>"\xA2", "\xBE"=>"\xA5",
  "\xBF"=>"\xA0", "\xC0"=>"\xA0", "\xC1"=>"\xA0", "\xC2"=>"\xA0", "\xC3"=>"\xA0", "\xC4"=>"\xA0", "\xC5"=>"\xA0",
  "\xC6"=>"\xE3", "\xC7"=>"\xC3", "\xC8"=>"\xA0", "\xC9"=>"\xA0", "\xCA"=>"\xA0", "\xCB"=>"\xA0", "\xCC"=>"\xA0",
  "\xCD"=>"\xA0", "\xCE"=>"\xA0", "\xCF"=>"\xA4", "\xD0"=>"\xF0", "\xD1"=>"\xD0", "\xD2"=>"\xCA", "\xD3"=>"\xCB",
  "\xD4"=>"\xC8", "\xD5"=>"\xA0", "\xD6"=>"\xCD", "\xD7"=>"\xCE", "\xD8"=>"\xCF", "\xD9"=>"\xA0", "\xDA"=>"\xA0",
  "\xDB"=>"\xA0", "\xDC"=>"\xA0", "\xDD"=>"\xA6", "\xDE"=>"\xCC", "\xDF"=>"\xA0", "\xE0"=>"\xD3", "\xE1"=>"\xDF",
  "\xE2"=>"\xD4", "\xE3"=>"\xD2", "\xE5"=>"\xD5", "\xE6"=>"\xB5", "\xE7"=>"\xFE", "\xE8"=>"\xDE", "\xE9"=>"\xDA",
  "\xEA"=>"\xDB", "\xEB"=>"\xD9", "\xEC"=>"\xFD", "\xED"=>"\xDD", "\xEE"=>"\xAF", "\xEF"=>"\xB4", "\xF0"=>"\xAD",
  "\xF1"=>"\xB1", "\xF2"=>"\xA0", "\xF3"=>"\xBE", "\xF4"=>"\xB6", "\xF5"=>"\xA7", "\xF6"=>"\xF7", "\xF7"=>"\xB8",
  "\xF8"=>"\xB0", "\xF9"=>"\xA8", "\xFA"=>"\xB7", "\xFB"=>"\xB9", "\xFC"=>"\xB3", "\xFD"=>"\xB2", "\xFE"=>"\xA0",
  "\xFF"=>"\xA0", "\x86"=>"\x40");
ripat

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

17 juil. 2007, 17:23

Bonjour,

Si tu as souvent les mêmes mots qui reviennent dans tes exports, alors peut être peux tu construire une mini-bdd qui ira convertir directement mot-à-mot (et caractère par caractère quand le mot est inconnu dans ton index).
Ce n'est pas une solution miracle mais ça peut permettre d'accélerer ton traitement.

Sinon, peux tu nous fournir un exemple de tes fichiers textes, je ne suis pas un expert en codepage mais je peux jeter un oeil si tu veux.
Quand tout le reste a échoué, lisez le mode d'emploi...

ViPHP
ViPHP | 5924 Messages

17 juil. 2007, 18:43

Si jamais tu n'as pas le charset exact mais juste une table de transcription, tu peux peut être envisager pour accélerer la transription une fonction en C, ou alors une équation logique (c'est facile à construire avec une table de Karnaugh par exemple) qui est peut être plus rapide...
Sinon, autre idée, plutôt que de rechercher dans une table de hashage , ce serait plus rapide de rechercher dans un tableau numérique, suffit juste de passer des index hexadécimaux plutôt que des index alphanumériques...

Mammouth du PHP | 19672 Messages

17 juil. 2007, 19:08

De mon coté, j'ai senti le JavaScript. J'ai fait ceci à partir de ton tableau :
<?php
echo("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" xml:lang="fr" />
<title></title>
</head>
<body>
<?php
$array_cp850 = array(

  "\x80"=>"\xC7", "\x81"=>"\xFC", "\x82"=>"\xE9", "\x83"=>"\xE2", "\x84"=>"\xE4", "\x85"=>"\xE0", "\x86"=>"\xE5",
  "\x87"=>"\xE7", "\x88"=>"\xEA", "\x89"=>"\xEB", "\x90"=>"\xC9", "\x91"=>"\xE6", "\x92"=>"\xC6", "\x93"=>"\xF4",
  "\x94"=>"\xF6", "\x95"=>"\xF2", "\x96"=>"\xFB", "\x97"=>"\xF9", "\x98"=>"\xFF", "\x99"=>"\xD6", "\x8A"=>"\xE8",
  "\x8B"=>"\xEF", "\x8C"=>"\xEE", "\x8D"=>"\xEC", "\x8E"=>"\xC4", "\x8F"=>"\xC5", "\x9A"=>"\xDC", "\x9B"=>"\xF8",
  "\x9C"=>"\xA3", "\x9D"=>"\xD8", "\x9E"=>"\xD7", "\x9F"=>"\xA0", "\xA0"=>"\xE1", "\xA1"=>"\xED", "\xA2"=>"\xF3",
  "\xA3"=>"\xFA", "\xA4"=>"\xF1", "\xA5"=>"\xD1", "\xA6"=>"\xAA", "\xA7"=>"\xBA", "\xA8"=>"\xBF", "\xA9"=>"\xAE",
  "\xAA"=>"\xAC", "\xAB"=>"\xBD", "\xAC"=>"\xBC", "\xAD"=>"\xA1", "\xAE"=>"\xAB", "\xAF"=>"\xBB", "\xB0"=>"\xA0",
  "\xB1"=>"\xA0", "\xB2"=>"\xA0", "\xB3"=>"\xA0", "\xB4"=>"\xA0", "\xB5"=>"\xC1", "\xB6"=>"\xC2", "\xB7"=>"\xC0",
  "\xB8"=>"\xA9", "\xB9"=>"\xA0", "\xBA"=>"\xA0", "\xBB"=>"\xA0", "\xBC"=>"\xA0", "\xBD"=>"\xA2", "\xBE"=>"\xA5",
  "\xBF"=>"\xA0", "\xC0"=>"\xA0", "\xC1"=>"\xA0", "\xC2"=>"\xA0", "\xC3"=>"\xA0", "\xC4"=>"\xA0", "\xC5"=>"\xA0",
  "\xC6"=>"\xE3", "\xC7"=>"\xC3", "\xC8"=>"\xA0", "\xC9"=>"\xA0", "\xCA"=>"\xA0", "\xCB"=>"\xA0", "\xCC"=>"\xA0",
  "\xCD"=>"\xA0", "\xCE"=>"\xA0", "\xCF"=>"\xA4", "\xD0"=>"\xF0", "\xD1"=>"\xD0", "\xD2"=>"\xCA", "\xD3"=>"\xCB",
  "\xD4"=>"\xC8", "\xD5"=>"\xA0", "\xD6"=>"\xCD", "\xD7"=>"\xCE", "\xD8"=>"\xCF", "\xD9"=>"\xA0", "\xDA"=>"\xA0",
  "\xDB"=>"\xA0", "\xDC"=>"\xA0", "\xDD"=>"\xA6", "\xDE"=>"\xCC", "\xDF"=>"\xA0", "\xE0"=>"\xD3", "\xE1"=>"\xDF",
  "\xE2"=>"\xD4", "\xE3"=>"\xD2", "\xE5"=>"\xD5", "\xE6"=>"\xB5", "\xE7"=>"\xFE", "\xE8"=>"\xDE", "\xE9"=>"\xDA",
  "\xEA"=>"\xDB", "\xEB"=>"\xD9", "\xEC"=>"\xFD", "\xED"=>"\xDD", "\xEE"=>"\xAF", "\xEF"=>"\xB4", "\xF0"=>"\xAD",
  "\xF1"=>"\xB1", "\xF2"=>"\xA0", "\xF3"=>"\xBE", "\xF4"=>"\xB6", "\xF5"=>"\xA7", "\xF6"=>"\xF7", "\xF7"=>"\xB8",
  "\xF8"=>"\xB0", "\xF9"=>"\xA8", "\xFA"=>"\xB7", "\xFB"=>"\xB9", "\xFC"=>"\xB3", "\xFD"=>"\xB2", "\xFE"=>"\xA0",
  "\xFF"=>"\xA0", "\x86"=>"\x40");
$chaine = "var array_cp850 = new Array;\n";
$i = 0;
foreach($array_cp850 as $cle => $val)
{
    $chaine .= "array_cp850[". $i ."] = new Array;\n";
    $chaine .= "array_cp850[". $i ."]['cle'] = '". $cle ."'\n";
    $chaine .= "array_cp850[". $i ."]['val'] = '". $val ."'\n";
    $i++;
}
echo('<script type="text/javascript">' . "\n");
echo('/* <![CDATA[ */' . "\n");
echo($chaine);
echo('var n = array_cp850.length;' . "\n");
echo('for(var i = 0; i < n; i++)' . "\n");
echo('{' . "\n");
echo("    document.write('Clé : '+ array_cp850[i]['cle'] +'; Valeur : '+ array_cp850[i]['val'] +';<br \/>\\n');\n");
echo('}' . "\n");
echo('/* ]]> */' . "\n");
echo("</script>\n");
?>
</body>
</html>
Et j'ai obtenu ceci :
[quote]Clé : €; Valeur : Ç;
Clé :
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

17 juil. 2007, 20:36

Je ne sais pas à quoi correspond ce charset, mais si tu cherches à améliorer les performances, remplacer ton tableau par une chaîne devrait à peu près décupler les performances. (c'est possible puisqu'il s'agit apparemment d'un encodage "single-byte")
$from = implode('', array_keys($array_cp850));
$to = implode('', $array_cp850);

strtr($str, $from, $to);
Au niveau des perfs, l'ordre des caractères a aussi son importance, je cherche dans mes sources et je te rapporte un truc utile. De ton côté, essaie de remplacer ton tableau par les chaînes générées comme ci-dessus et rapporte-nous le facteur de performance, moi ça m'intéresse ;)

ViPHP
ViPHP | 1380 Messages

17 juil. 2007, 21:58

Merci à tous pour vos réponses, je me suis absenté pour le boulot et je reprends le truc.

@rthur: il s'agit d'un fichier client. Peu de mots semblables, surtout par chez nous avec les Vanderweghen, Van der Wegen, Hendrieckx, Hendrieks, Hendrikx etc...

Sékiltoyai: oui, en c, mais il faudrait que je l'apprenne surtout.

Cyrano, mon mapping marche apparemment bien mais ce qui m'énerve c'est de ne pas trouver le set original.

Hubert R, j'ai déjà fait des essais par le passé et j'ai le souvenir qu'un strtr sur un tableau était plus rapide que sur une chaîne, par contre j'achète l'idée de hierarchiser sur la fréquence des caractères, mais là encore, avec les patronymes qu'on a chez nous...

Je pense que je vais prendre un charset approchant dans iconv, (il y en a 962 tout de même - iconv -l) et compléter par un sed ou tr sur les caractères manquant. Ce sont des commandes linux qui sont plus proche de leurs sources c que les fonctions PHP.

[coup de gueule]
Mais je commence a en avoir assez de tous ces problèmes d'accents, de locales et autres charset. Le monde n'a qu'à utiliser une seule langue après tout. Le Français par exemple! Elle est tellement belle notre langue. Bon, c'est vrai il faudra la débarrasser des quelques cédilles, trémas et accents circonflexes mais on fera l'effort. Et puis, tant qu'à faire, je demande aussi à tous mes compatriotes du nord du rideau de betteraves de changer de nom. Dupont, ou à la rigueur, Dupond mais plus de Mijnheer Vanalderweghen gaat naar de ottentottententententoonstelling..
[/coup de gueule]

Aaah, je me sens mieux du coup!

Je vais essayer vos pistes et vous revenir avec les résultats de mes tests.

:wink:
ripat

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

17 juil. 2007, 22:23

j'ai le souvenir qu'un strtr sur un tableau était plus rapide que sur une chaîne, par contre j'achète l'idée de hierarchiser sur la fréquence des caractères
Pour le tableau vs chaîne, ça dépend de ta version de PHP, mais d'après mes tests rapides vous PHP 5.2 le facteur de performance est de 1 pour 20 en faveur des chaîne. En revanche, pas d'amélioration notable par le réagencement des caractères, probablement parce que les caractères les plus courants ne figurent pas dans ta table.

Je te donne quand même l'algo au cas où. Soit $txt un échantillon de texte représentatif de tes fichiers
$from = $to = '';
$chars = count_chars($txt, 0);
arsort($chars);

foreach ($chars as $ord => $n)
{
	$c = chr($ord);

	if (!isset($array_cp850[$c]))
	{
		continue;
	}

	$from .= $c;
	$to .= $array_cp850[$c];
}
Je pense que je vais prendre un charset approchant dans iconv [...] et compléter par un sed ou tr
J'y pensais aussi, mais vu que ton codepage semble être un superset d'ASCII et que les caractères les plus courants (a-z, l'espace) n'y figurent pas tu risques de n'avoir qu'un gain très modeste. Idéalement, regarde si tu peux créer ton propre codepage pour iconv, et tu seras fixé une fois pour toute ?

Au sujet des commandes shell "plus proches" que PHP, si ton traitement se fait sur un petit nombre de gros fichiers je ne pense pas que tu aies un gros avantage. S'il s'agit d'un grand nombre de fichiers oui, mais sinon j'en doute donc je te conseillerais d'utiliser le plus facile/pratique.

ViPHP
ViPHP | 1380 Messages

18 juil. 2007, 12:28

J'ai renoncé à trouver le set de caractères du fichier d'origine, je suis donc condamné (con damné?) à convertir à partir d'un set approchant (ici CP850) et ensuite remplacer les caractères non reconnus tel que \x86 --> @

Merci à tous en particulier à Hubert car, effectivement un strtr() avec des chaînes plutôt qu'un tableau comme arguments de remplacement et de l'ordre de 10x plus rapide dans mes essais.

Code : Tout sélectionner

0.298682928085 sec. strtr tableau 0.0246140956879 sec. strtr string 0.0434939861298 sec. iconv pipé dans un tr "\345" @
Malgré ces résultats, je vais passer à iconv+tr car je vais devoir bientôt traiter de *très gros* fichiers et je ne pense pas avoir suffisamment de mémoire pour mettre ces fichiers en une fois dans un string pour traitement par strtr(). On pourrait travailler avec un flux sur ces gros fichiers mais je pense que ça sera plus lent que iconv.
ripat

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

18 juil. 2007, 19:29

Pour info, j'ai fait quelques tests par curiosité, l'occasion pour moi de m'essayer aux "stream filters", que je connaissais de réputation sans jamais les avoir essayé. Sur un fichier de quelques MiB, et d'après "time", un script PHP utilisant stream_filter était 10-20% plus rapide qu'un iconv+tr, le tout en ligne de commande. L'ordi sur lequel j'ai testé faisait d'autres choses donc les résultats absolus ne sont pas stables, mais l'écart lui l'était.

Pour référence, le stream filter (appelé "codepage") pour convertir le codepage exotique en iso-8859-1
class codepage_filter extends php_user_filter
{
	public function filter($in, $out, &$consumed, $closing)
	{
		while ($bucket = stream_bucket_make_writeable($in))
		{
			$bucket->data = strtr(
				$bucket->data,
				"\xE9\xE7\xE8\xF4\xEE\xEB\xE2\xEA\xB0\xDC\xC3\xCD\xC2\xC8\xC9\xA7\xCA\xCB\xCC\xA8\xC5\xC6\xC7\xC4\xBF\xB3\xB2\xB4\xB5\xB6\xB1\xAF\xAA\xAC\xAD\xAE\xB7\xB8\xBE\xAB\xC0\xC1\xBD\xCE\xB9\xBA\xBB\xBC\xA9\xF2\xF9\xE0\xFE\xDF\xE1\xA6\xE3\xF8\xDE\xFD\xD9\xDA\xDB\xD8\xD7\xDD\xFA\xFC\xF7\xE5\xFF\xFB\xF1\xF3\xF5\xD0\xD1\xF6\xF0\xEF\xD5\xD6\xE6\xD4\xD3\xED\xEC\xD2\xCF\x96\x97\x98\x99\x95\x94\x90\x91\x92\x93\x9A\x9B\xA1\xA2\xA3\xA4\xA0\x9F\x9C\x9D\x9E\x8F\x8E\x80\x81\x82\x83\x84\x8A\x8B\x8C\x8D\x89\x88\x85\x86\x87\xA5",
				"\xDA\xFE\xDE\xB6\xAF\xD9\xD4\xDB\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xBA\xA0\xA0\xA0\xBF\xA0\xE3\xC3\xA0\xA0\xA0\xA0\xA0\xC1\xC2\xA0\xBB\xAC\xBC\xA1\xAB\xC0\xA9\xA5\xBD\xA0\xA0\xA2\xA0\xA0\xA0\xA0\xA0\xAE\xA0\xA8\xD3\xA0\xA0\xDF\xAA\xD2\xB0\xCC\xB2\xA0\xA0\xA0\xCF\xCE\xA6\xB7\xB3\xB8\xD5\xA0\xB9\xB1\xBE\xA7\xF0\xD0\xF7\xAD\xB4\xA0\xCD\xB5\xC8\xCB\xDD\xFD\xCA\xA4\xFB\xF9\xFF\xD6\xF2\xF6\xC9\xE6\xC6\xF4\xDC\xF8\xED\xF3\xFA\xF1\xE1\xA0\xA3\xD8\xD7\xC5\xC4\xC7\xFC\xE9\xE2\xE4\xE8\xEF\xEE\xEC\xEB\xEA\xE0\x40\xE7\xD1"				
			);
			$consumed += $bucket->datalen;
			stream_bucket_append($out, $bucket);
		}
		return PSFS_PASS_ON;
	}
}
stream_filter_register('codepage', 'codepage_filter');
Faire une copie du fichier tout en appliquant le filtre:
$r = fopen('./sample.txt', 'rb');
$w = fopen('./sample2.txt', 'wb');

stream_filter_append($r, 'codepage');
stream_copy_to_stream($r, $w);
Et puisqu'il s'agit d'une copie de stream, PHP procède par blocs de 8 KiB automatiquement (je crois me rappeler qu'on peut changer cette valeur, mais je ne sais plus comment).

L'avantage d'un tel filtre est qu'on peut l'appliquer de façon transparente. Une fois stream_filter_append() appliqué au stream (celui qui lit le fichier exotique), c'est comme si on lisait à partir du fichier converti. Et pour les cas où stream_filter_append() ne peut être utilisé, on peut utiliser le pseudo-protocol "php". Par exemple, pour lire le fichier exotique /tmp/sample1.txt comme s'il s'agissait du fichier converti:
file_get_contents('php://filter/read=codepage/resource=file:///tmp/sample1.txt')
Reste que si seules les performances comptent, j'ai eu les meilleurs résultats avec cette routine (plus simple, et avec un plus gros buffer)
$r = fopen('./sample.txt', 'rb');
$w = fopen('./sample2.txt', 'wb');
stream_set_write_buffer($w, 262144);

while (!feof($r))
{
	fwrite($w, strtr(
		fread($r, 262144),
		"\xE9\xE7\xE8\xF4\xEE\xEB\xE2\xEA\xB0\xDC\xC3\xCD\xC2\xC8\xC9\xA7\xCA\xCB\xCC\xA8\xC5\xC6\xC7\xC4\xBF\xB3\xB2\xB4\xB5\xB6\xB1\xAF\xAA\xAC\xAD\xAE\xB7\xB8\xBE\xAB\xC0\xC1\xBD\xCE\xB9\xBA\xBB\xBC\xA9\xF2\xF9\xE0\xFE\xDF\xE1\xA6\xE3\xF8\xDE\xFD\xD9\xDA\xDB\xD8\xD7\xDD\xFA\xFC\xF7\xE5\xFF\xFB\xF1\xF3\xF5\xD0\xD1\xF6\xF0\xEF\xD5\xD6\xE6\xD4\xD3\xED\xEC\xD2\xCF\x96\x97\x98\x99\x95\x94\x90\x91\x92\x93\x9A\x9B\xA1\xA2\xA3\xA4\xA0\x9F\x9C\x9D\x9E\x8F\x8E\x80\x81\x82\x83\x84\x8A\x8B\x8C\x8D\x89\x88\x85\x86\x87\xA5",
		"\xDA\xFE\xDE\xB6\xAF\xD9\xD4\xDB\xA0\xA0\xA0\xA0\xA0\xA0\xA0\xBA\xA0\xA0\xA0\xBF\xA0\xE3\xC3\xA0\xA0\xA0\xA0\xA0\xC1\xC2\xA0\xBB\xAC\xBC\xA1\xAB\xC0\xA9\xA5\xBD\xA0\xA0\xA2\xA0\xA0\xA0\xA0\xA0\xAE\xA0\xA8\xD3\xA0\xA0\xDF\xAA\xD2\xB0\xCC\xB2\xA0\xA0\xA0\xCF\xCE\xA6\xB7\xB3\xB8\xD5\xA0\xB9\xB1\xBE\xA7\xF0\xD0\xF7\xAD\xB4\xA0\xCD\xB5\xC8\xCB\xDD\xFD\xCA\xA4\xFB\xF9\xFF\xD6\xF2\xF6\xC9\xE6\xC6\xF4\xDC\xF8\xED\xF3\xFA\xF1\xE1\xA0\xA3\xD8\xD7\xC5\xC4\xC7\xFC\xE9\xE2\xE4\xE8\xEF\xEE\xEC\xEB\xEA\xE0\x40\xE7\xD1"
	));
}
fclose($r);
fclose($w);

ViPHP
ViPHP | 1380 Messages

18 juil. 2007, 19:49

Intéressant tout ça. Je le garde sous le coude et testerai en conditions réelles sous peu. :wink:

un iconv + tr est logiquement plus lent car il doit faire le travail deux fois. Une fois pour la conversion de codeset standard et une deuxième pour les caractères exotiques. Il y a donc deux passages sur chaque ligne. Ai essayé sed (après iconv) aussi mais il est encore plus lent. Tiens, je vais essayer un tr avec la matrice du strtr() pour voir.
ripat

ViPHP
ViPHP | 1380 Messages

21 juil. 2007, 11:01

Restait donc deux solutions pour les gros fichiers:
  • Un strtr() du type string avec une gestion des flux avec un gros tampon (exemple d'Hubert plus haut)
  • Un tr (linux) sur la même matrice de mapping mais convertie en octal:

    Code : Tout sélectionner

    #!/bin/sh # # conversion de fichier --> ISO8859-1 # FROM="\200\201 ... etc... \376\377" TO="\307\374 ... etc...\240\240" cat fichier_in | tr "$FROM" "$TO" > fichier_out
Taille du fichier test: 59 Mo (un million de lignes)

Résultats:
0.65884 sec. array string
0.49366 sec. tr

Léger avantage au tr de coreutils (25% plus rapide). Mais je m'attendais à bien pire de la part du strtr de PHP qui se défend très bien. Bon, c'est vrai que le code est un peu plus lourd, mais pas mal quand même. Dans les deux cas, une demi seconde pour analyser chaque caractère d'un fichier d'un million de lignes - 60 millions de caractères!

Moi qui ai connu l'époque de la plume et de la gomme... :wink:

Mais je n'ai toujours pas trouvé le charset du fichier. J'ai interrogé la société. Le fichier est généré par un SGBD Caché (le SGBD "Le plus rapide du monde!" ) :^o

Quelqu'un connaît?
ripat

Mammouth du PHP | 19672 Messages

21 juil. 2007, 11:44

Je ne sais pas si ça peut éclairer ta lanterne, mais en fouillant un peu, j'ai trouvé d'abord ceci et également ceci, mais là, c'est du C et je ne suis pas certain que ce soit très utile en l'occurence :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

21 juil. 2007, 16:04

Mais je n'ai toujours pas trouvé le charset du fichier. J'ai interrogé la société. Le fichier est généré par un SGBD Caché
En cherchant dans leur newsgroup, j'ai trouvé quelques références à EBCDIC, as-tu cherché de ce côté là?
Quand tout le reste a échoué, lisez le mode d'emploi...

ViPHP
ViPHP | 1380 Messages

22 juil. 2007, 18:37

Je ne sais pas si ça peut éclairer ta lanterne, mais en fouillant un peu, j'ai trouvé d'abord ceci et également ceci, mais là, c'est du C et je ne suis pas certain que ce soit très utile en l'occurence :-k
Merci. J'ai de plus en plus l'impression que le sagouin qui a écrit le code d'export du fichier a mélangé deux codeset différents. Je vais essayer de le joindre par téléphone la semaine prochaine pour lui dire tout le bien que je pense de son utilisation des charset standards...
En cherchant dans leur newsgroup, j'ai trouvé quelques références à EBCDIC, as-tu cherché de ce côté là?
Oui, j'ai essayé les 46 charset EBCDIC d'iconv.
ripat

Eléphant du PHP | 217 Messages

25 juil. 2007, 08:03

Salut,
si tu a acces à un shell Linux tu peux peut-etre voir l'encodage utilisé à l'aide de la commande file :
$ file fichier.txt
fichier.txt: UTF-8 Unicode HTML document text, with CRLF line terminators

ensuite essais de convertir le fichier avec iconv en ligne de commande toujours :
$ iconv --from-code=UTF-8 --to-code=ISO-8859-1 fichier.txt fichier2.txt

Si ca ne sufit pas essais avec l'utilitaire utrac :
http://utrac.sourceforge.net