Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Convertir un fichier de Mac Roman en UTF-8

19 réponses
Avatar
Sebastien
Bonjour à tous,

Je dois exploiter un fichier issu d'une Bas de données sous Mac. Je
reçois un fichier type CSV qui est très probablement codé en MAC OS
ROMAN, du moins il n'est pas en Latin-1, Windows-1252, ni UTF-8, car il
produit des caractères non reconnus.

Je passe sur le pourquoi, disons que je dois m'efforcer d'afficher ce
contenu dans des pages web qui seront en UTF-8.

J'ai touuvé (dans les contributions de http://fr3.php.net/htmlentities)
cette fonction qui encode en ISO-8859-1 :

<?php
/**
* Converts MAC OS ROMAN encoded strings to the ISO 8859-1 charset.
*
* @param string the string to convert.
* @return string the converted string.
*/
function mac_roman_to_iso($string)
{
return strtr($string,
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa1\xa4\xa6\xa7\xa8\xab\xac\xae\xaf\xb4\xbb\xbc\xbe\xbf\xc0\xc1\xc2\xc7\xc8\xca\xcb\xcc\xd6\xd8\xdb\xe1\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf1\xf2\xf3\xf4\xf8\xfc\xd2\xd3\xd4\xd5Ð",
"\xc4\xc5\xc7\xc9\xd1\xd6\xdc\xe1\xe0\xe2\xe4\xe3\xe5\xe7\xe9\xe8\xea\xeb\xed\xec\xee\xef\xf1\xf3\xf2\xf4\xf6\xf5\xfa\xf9\xfb\xfc\xb0\xa7\xb6\xdf\xae\xb4\xa8\xc6\xd8\xa5\xaa\xba\xe6\xf8\xbf\xa1\xac\xab\xbb\xa0\xc0\xc3\xf7\xff\xa4\xb7\xc2\xca\xc1\xcb\xc8\xcd\xce\xcf\xcc\xd3\xd4\xd2\xda\xdb\xd9\xaf\xb8\x22\x22\x27\x27-");
}
?>

Ensuite j'utilise quelque chose comme :

mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1');

pour passer en UTF-8.

Cela fonctionne assez bien mais le problème est qu'il reste des
caractères non reconnus, ou plutôt mal reconnus. Je suppose que la
focntion ne convertit pas tous les caractères problématiques, mais je
n'ai pas réussi à la modifier correctement (lorsque je rajoute des
caractères j'obtiens de résultats inattendus alors que je suis le
tableau de http://en.wikipedia.org/wiki/Mac_OS_Roman).

J'ai essayé de reproduire une fonction qui convertirait directement en
UTF-8 (avec les infos trouvées sur :
http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT) mais ça
ne fonctionne pas. De nombreuses subtilités doivent m'échapper.

PHP peut-il encoder directement du MAC ROMAN en ISO ? Connaissez-vous
une méthode efficace pour pallier le manque éventuel des fonctions
natives de PHP ?

Merci de votre aide,

Sébastien

10 réponses

1 2
Avatar
Olivier Miakinen

Je dois exploiter un fichier issu d'une Bas de données sous Mac. Je
reçois un fichier type CSV qui est très probablement codé en MAC OS
ROMAN, du moins il n'est pas en Latin-1, Windows-1252, ni UTF-8, car il
produit des caractères non reconnus.

Je passe sur le pourquoi, disons que je dois m'efforcer d'afficher ce
contenu dans des pages web qui seront en UTF-8.

[...]

PHP peut-il encoder directement du MAC ROMAN en ISO ? Connaissez-vous
une méthode efficace pour pallier le manque éventuel des fonctions
natives de PHP ?


As-tu essayé avec iconv() <http://fr2.php.net/iconv&gt; pour encoder
directement de MacRoman en UTF-8 ?

Avatar
Sebastien
As-tu essayé avec iconv() <http://fr2.php.net/iconv&gt; pour encoder
directement de MacRoman en UTF-8 ?


Je ne pense pas qu'il soit possible d'installer iconv sur cet
hébergement mutualisé (OVH).

Sébastien

Avatar
Olivier Miakinen
As-tu essayé avec iconv() <http://fr2.php.net/iconv&gt; pour encoder
directement de MacRoman en UTF-8 ?


Je ne pense pas qu'il soit possible d'installer iconv sur cet
hébergement mutualisé (OVH).


Pose quand même la question, il est très possible qu'il soit présent par
défaut (d'après la doc, c'est toujours le cas en PHP5).


Sinon, tu peux regarder par exemple ici :
<http://www.alanwood.net/demos/macroman.html&gt;.

Il suffit (!) de faire une fonction PHP qui remplace les caractères dont
les numéros vont de 128 à 255, soit par l'entité nommée HTML, soit par
l'entité numérique HTML (en décimal ou en hexa), soit par l'encodage
UTF-8 correspondant au numéro du caractère. Pour les caractères compris
entre 32 et 126 il n'y a rien à faire (pour ceux-là, on a MacRoman ASCII = UTF-8).

Je prends comme exemple le premier caractère au dela d'ASCII, celui de
numéro 128.

Le tableau t'indique :
Character : Ä
Macintosh Number : 128
Unicode Number : 196
Macintosh Hex : 0x80
Unicode Hex : U+00C4
HTML 4.0 Entity : &Auml;

Tu peux donc remplacer un caractère dont le numéro est 128 (0x80 en
hexa), soit par la chaîne &Auml; (directement l'entité HTML 4.0),
soit par la chaîne &#196; ('&' + '#' + Unicode Number + ';'), soit
par la chaîne &#xC4; ('&' + '#' + 'x' + Unicode hex + ';'), soit par
la transformation UTF-8 du numéro 196. Je suppose que le code existe
tout fait quelque part, mais je ne l'ai pas trouvé sur le net.


Bon, mais ce serait quand même plus simple si ton hébergement OVH avait
iconv d'installé !


Avatar
dwojylac.nospam
Sebastien wrote:

Je dois exploiter un fichier issu d'une Bas de données sous Mac. Je
reçois un fichier type CSV qui est très probablement codé en MAC OS
ROMAN, du moins il n'est pas en Latin-1, Windows-1252, ni UTF-8, car il
produit des caractères non reconnus.

Je passe sur le pourquoi, disons que je dois m'efforcer d'afficher ce
contenu dans des pages web qui seront en UTF-8.


Ton fichier si je comprends bien tu peux le convertir en local sur ta
machine avant de le télécharger ou de l'exploiter...
Donc tu dois pouvoir trouver un logiciel qui permette de lire du Mac
Roman et d'enregistrer en UTF-8
Dans ce cas TextEdit est tout à fait utilisable (voir les options
d'ouverture et d'enregistrement dans les dialogues correspondants) ou
TextWrangler <http://www.barebones.com/&gt; ou SubEthaEdit (tu peux te
contenter de la version free 2.2
<http://www.codingmonkeys.de/subethaedit/old.html&gt;

--
Dominique Wojylac http://wojylac.free.fr
Un proverbe chinois dit que lorsqu'on a rien à dire
on cite généralement un proverbe chinois.

Avatar
Olivier Miakinen

Je dois exploiter un fichier issu d'une Bas de données sous Mac. Je
reçois un fichier type CSV qui est très probablement codé en MAC OS
ROMAN, du moins il n'est pas en Latin-1, Windows-1252, ni UTF-8, car il
produit des caractères non reconnus.

Je passe sur le pourquoi, disons que je dois m'efforcer d'afficher ce
contenu dans des pages web qui seront en UTF-8.


Ton fichier si je comprends bien tu peux le convertir en local sur ta
machine avant de le télécharger ou de l'exploiter...


Bon sang mais c'est bien sûr !

Donc tu dois pouvoir trouver un logiciel qui permette de lire du Mac
Roman et d'enregistrer en UTF-8


Pas mieux. ©


Avatar
Sebastien
Ton fichier si je comprends bien tu peux le convertir en local sur ta
machine avant de le télécharger ou de l'exploiter...


Si seulement ! Merci beaucoup pour ces suggestsions, mais...

Il s'agit en fait d'un fichier qui sera uploadé par la personne qui
exporte ledit fichier depuis l'application sur son Mac. L'upload se fait
donc sur le Mac à travers un formulaire web HTML.

L'objectif est que cette personne ait un minimum de manipulations
"techniques" à faire. Exporter au bon format et uploader est donc en
quelque sorte le max. que je puisse exiger...

Quant à moi, pour simplifier les choses, je travaille sur PC et j'ai un
minimum de connaissances du monde Mac.

Revenons au problème PHP. Les suggestions d'Olivier m'ont (une fois de
plus !) permis d'avancer.

J'ai écris une fonction qui transforme les caractères MacRoman en
entités numériques hexadécimales ISO-10646.

function mac_roman_to_unicode($str)
{
return strtr($str, array("x80"=>"&#xC4;", "x81"=>"&#xC5;",
"x82"=>"&#xC7;", "x83"=>"&#xC9;", "x84"=>"&#xD1;", "x85"=>"&#xD6;",
"x86"=>"&#xDC;", "x87"=>"&#xE1;", "x88"=>"&#xE0;", "x89"=>"&#xE2;",
"x8A"=>"&#xE4;", "x8B"=>"&#xE3;", "x8C"=>"&#xE5;", "x8D"=>"&#xE7;",
"x8E"=>"&#xE9;", "x8F"=>"&#xE8;", "x90"=>"&#xEA;", [...]));
}

Passons peut-être sur les possibilités d'optimisation de cette fonction.

Cela fonctionne mais je me retrouve avec des entitiés qui limiteront
voire empêcheront carrément les possibilités de recherches en mode texte
(ai-je oublié de préciser que tout ceci se retrouve dans une base de
données ?).
Il faudrait donc convertir ces entités numériques en caractères UTF-8.
C'est peut-être là que quelque chose m'échappe, car la conversion :
"x80"=>"xC4" ne fonctionne pas. J'ai essayé avec "x80"=>"
Avatar
Olivier Miakinen

Il s'agit en fait d'un fichier qui sera uploadé par la personne qui
exporte ledit fichier depuis l'application sur son Mac. L'upload se fait
donc sur le Mac à travers un formulaire web HTML.


Ah oui, pas glop.

[...]

function mac_roman_to_unicode($str)
{
return strtr($str, array("x80"=>"&#xC4;", "x81"=>"&#xC5;",
"x82"=>"&#xC7;", "x83"=>"&#xC9;", "x84"=>"&#xD1;", "x85"=>"&#xD6;",
"x86"=>"&#xDC;", "x87"=>"&#xE1;", "x88"=>"&#xE0;", "x89"=>"&#xE2;",
"x8A"=>"&#xE4;", "x8B"=>"&#xE3;", "x8C"=>"&#xE5;", "x8D"=>"&#xE7;",
"x8E"=>"&#xE9;", "x8F"=>"&#xE8;", "x90"=>"&#xEA;", [...]));
}

[...]
Il faudrait donc convertir ces entités numériques en caractères UTF-8.
C'est peut-être là que quelque chose m'échappe, car la conversion :
"x80"=>"xC4" ne fonctionne pas. J'ai essayé avec "x80"=>"
Avatar
Olivier Miakinen

Je prends comme exemple le premier caractère au dela d'ASCII, celui de
numéro 128.

Le tableau t'indique :
Character : Ä
Macintosh Number : 128
Unicode Number : 196
Macintosh Hex : 0x80
Unicode Hex : U+00C4
HTML 4.0 Entity : &Auml;

Tu peux donc remplacer un caractère dont le numéro est 128 (0x80 en
hexa), soit par [...], soit par la transformation UTF-8 du numéro 196.


... c'est-à-dire code2utf(196) = "xC3x84"

--
Olivier Miakinen
Troll du plus sage chez les conviviaux : le nouveau venu, avec
son clan, s'infiltre dans les groupes de nouvelles. (3 c.)

Avatar
Sebastien
Normal. Une idée pour avancer : faire une fois pour toute la conversion
de chaque caractère MacRoman vers UTF-8, en t'aidant de ce que tu as déjà.

Ainsi,
1) "x80" => "&#xC4;" (ta fonction mac_roman_to_unicode)
2) "&#xC4;" => 0xC4 (facile)
3) 0xC4 => "xC3x84" (la fonction code2utf)

D'où :
"x80" => "xC3x84"

Tu le fais une fois pour chaque caractère, tu stockes le résultat dans
un tableau, et tu obtiens la fonction mac_roman_to_utf_8 (c'est un peu
de boulot, mais visiblement tu as le courage et le talent qu'il faut
pour le faire).


Merci Olivier, je ne sais pas si je m'en serais sorti sans ton aide, en
tout cas au bout de combien de temps... Merci pour le lien vers l'outil
de Richard Ishida, il me sera sûrement encore utlile.

Voici le résultat (final j'espère).

<?php
function macRoman_to_utf8($str)
{
return strtr($str, array("x80"=>"xC3x84", "x81"=>"xC3x85",
"x82"=>"xC3x87", "x83"=>"xC3x89", "x84"=>"xC3x91",
"x85"=>"xC3x96", "x86"=>"xC3x9C", "x87"=>"xC3xA1",
"x88"=>"xC3xA0", "x89"=>"xC3xA2", "x8A"=>"xC3xA4",
"x8B"=>"xC3xA3", "x8C"=>"xC3xA5", "x8D"=>"xC3xA7",
"x8E"=>"xC3xA9", "x8F"=>"xC3xA8", "x90"=>"xC3xAA",
"x91"=>"xC3xAB", "x92"=>"xC3xAD", "x93"=>"xC3xAC",
"x94"=>"xC3xAE", "x95"=>"xC3xAF", "x96"=>"xC3xB1",
"x97"=>"xC3xB3", "x98"=>"xC3xB2", "x99"=>"xC3xB4",
"x9A"=>"xC3xB6", "x9B"=>"xC3xB5", "x9C"=>"xC3xBA",
"x9D"=>"xC3xB9", "x9E"=>"xC3xBB", "x9F"=>"xC3xBC",
"xA0"=>"xE2x80xA0", "xA1"=>"xC2xB0", "xA2"=>"xC2xA2",
"xA3"=>"xC2xA3", "xA4"=>"xC2xA7", "xA5"=>"xE2x80xA2",
"xA6"=>"xC2xB6", "xA7"=>"xC3x9F", "xA8"=>"xC2xAE",
"xA9"=>"xC2xA9", "xAA"=>"xE2x84xA2", "xAB"=>"xC2xB4",
"xAC"=>"xC2xA8", "xAD"=>"xE2x89xA0", "xAE"=>"xC3x86",
"xAF"=>"xC3x98", "xB0"=>"xE2x88x9E", "xB1"=>"xC2xB1",
"xB2"=>"xE2x89xA4", "xB3"=>"xE2x89xA5", "xB4"=>"xC2xA5",
"xB5"=>"xC2xB5", "xB6"=>"xE2x88x82", "xB7"=>"xE2x88x91",
"xB8"=>"xE2x88x8F", "xB9"=>"xCFx80", "xBA"=>"xE2x88xAB",
"xBB"=>"xC2xAA", "xBC"=>"xC2xBA", "xBD"=>"xCExA9",
"xBE"=>"xE6", "xBF"=>"xC3xB8", "xC0"=>"xC2xBF",
"xC1"=>"xC2xA1", "xC2"=>"xC2xAC", "xC3"=>"xE2x88x9A",
"xC4"=>"xC6x92", "xC5"=>"xE2x89x88", "xC6"=>"xE2x88x86",
"xC7"=>"xC2xAB", "xC8"=>"xC2xBB", "xC9"=>"xE2x80xA6",
"xCA"=>"xC2xA0", "xCB"=>"xC3x80", "xCC"=>"xC3x83",
"xCD"=>"xC3x95", "xCE"=>"xC5x92", "xCF"=>"xC5x93",
"xD0"=>"xE2x80x93", "xD1"=>"xE2x80x94", "xD2"=>"xE2x80x9C",
"xD3"=>"xE2x80x9D", "xD4"=>"xE2x80x98", "xD5"=>"xE2x80x99",
"xD6"=>"xC3xB7", "xD7"=>"xE2x97x8A", "xD8"=>"xC3xBF",
"xD9"=>"xC5xB8", "xDA"=>"xE2x81x84", "xDB"=>"xE2x82xAC",
"xDC"=>"xE2x80xB9", "xDD"=>"xE2x80xBA", "xDE"=>"xEFxACx81",
"xDF"=>"xEFxACx82", "xE0"=>"xE2x80xA1", "xE1"=>"xC2xB7",
"xE2"=>"xE2x80x9A", "xE3"=>"xE2x80x9E", "xE4"=>"xE2x80xB0",
"xE5"=>"xC3x82", "xE6"=>"xC3x8A", "xE7"=>"xC3x81",
"xE8"=>"xC3x8B", "xE9"=>"xC3x88", "xEA"=>"xC3x8D",
"xEB"=>"xC3x8E", "xEC"=>"xC3x8F", "xED"=>"xC3x8C",
"xEE"=>"xC3x93", "xEF"=>"xC3x94", "xF0"=>"xEFxA3xBF",
"xF1"=>"xC3x92", "xF2"=>"xC3x9A", "xF3"=>"xC3x9B",
"xF4"=>"xC3x99", "xF5"=>"xC4xB1", "xF6"=>"xCBx86",
"xF7"=>"xCBx9C", "xF8"=>"xC2xAF", "xF9"=>"xCBx98",
"xFA"=>"xCBx99", "xFB"=>"xCBx9A", "xFC"=>"xC2xB8",
"xFD"=>"xCBx9D", "xFE"=>"xCBx9B", "xFF"=>"xCBx87"));
}
?>

Cette fonction est bien évidemment à la disposition de tous ceux qui en
auront besoin. Si vous trouvez des bugs, laissez un message.


Notes :
J'ai également trouvé dans le fichier source en MacRoman un caractère
semi-illégal en HTML (en dessous de U+0020), reconnu comme "vertical
tab" par certains éditeurs (c'est lui :
http://www.fileformat.info/info/unicode/char/000B/index.htm). J'ai
décidé de le transformer en espace : "xB"=>"x20" (mais il n'est pas
inclu dans la fonction).

Précision : ces caractères sont légaux en UNICODE mais pas autorisés en
SGML/HTML, sauf sous forme d'appel de caractère (&#xb; ou &#11;). La
forme "littérale" est interdite en HTML.

Donc pour les maniacs de la validation il faut aussi faire attention à
tous les caractères possibles car le validateur du W3C vous enverra
bouler en cas de caractère "non-SGML" : ce n'est pas parce qu'on a
correctement détecté un codage de caractères, que celui-ci sera toujours
valide/bien employé...


Sébastien

Avatar
Olivier Miakinen

Merci Olivier, je ne sais pas si je m'en serais sorti sans ton aide, en
tout cas au bout de combien de temps... Merci pour le lien vers l'outil
de Richard Ishida, il me sera sûrement encore utile.


Je ne sais pas si tu le connais déjà, mais voici un autre lien
indispensable quand on veut y comprendre quelque chose à Unicode et
UTF-8 (entre autres choses, tu y comprendras la fonction code2utf) :
<http://www.cl.cam.ac.uk/~mgk25/unicode.html&gt;.

Voici le résultat (final j'espère).

<?php
function macRoman_to_utf8($str)
{
return strtr($str, [...] "xDE"=>"xEFxACx81",
"xDF"=>"xEFxACx82", [...] "xF0"=>"xEFxA3xBF", [...]));
}
?>

Cette fonction est bien évidemment à la disposition de tous ceux qui en
auront besoin. Si vous trouvez des bugs, laissez un message.


Je n'ai pas eu le courage de tout décortiquer pour y trouver des bugs,
d'autant que je n'ai pas de Mac à ma disposition. En revanche, j'aurais
des petites remarques.

Tout d'abord, s'il est correct de considérer æ, Æ, ½ et ¼ comme des
caractères à part entière, je pense que ce n'est pas le cas des
ligatures fi et fl (qui ne sont que graphiques). Du coup, pour faire
des recherches en mode texte, un besoin que tu as exprimé, il serait
peut-être préférable de les « dé-lier » plutôt que d'aller chercher des
caractères dans la zone « Alphabetic Presentation Forms ». Quant au logo
Apple, tu peux peut-être le supprimer ou le transformer en espace (comme
tu fais avec le vertical tab).

Cela pourrait donc donner :
return strtr($str, [...] "xDE"=>"fi",
"xDF"=>"fl", [...] "xF0"=>"xEFxA3xBF", [...]));

Ou :
return strtr($str, [...] "xDE"=>"fi",
"xDF"=>"fl", [...] "xF0"=>" ", [...]));

Ou encore :
return strtr($str, [...] "xDE"=>"fi",
"xDF"=>"fl", [...] "xF0"=>"", [...]));

Notes :
J'ai également trouvé dans le fichier source en MacRoman un caractère
semi-illégal en HTML (en dessous de U+0020), reconnu comme "vertical
tab" par certains éditeurs (c'est lui :
http://www.fileformat.info/info/unicode/char/000B/index.htm). J'ai
décidé de le transformer en espace : "xB"=>"x20" (mais il n'est pas
inclu dans la fonction).


Tant que tu y es, tu peux aussi transformer en espace tout ce qui n'est
pas "x09" (tabulation), "x0A" (line feed) et "x0D" (carriage return).

Sinon, question de présentation, j'aurais écrit "x0B"=>" " plutôt que
"xB"=>"x20" (les goûts et les couleurs, toussa).

Précision : ces caractères sont légaux en UNICODE mais pas autorisés en
SGML/HTML, sauf sous forme d'appel de caractère (&#xb; ou &#11;). La
forme "littérale" est interdite en HTML.


Je doute que ce soit très légal sous forme d'appel de caractère...
Mais je n'ai pas trouvé de doc explicite.

Donc pour les maniacs de la validation il faut aussi faire attention à
tous les caractères possibles car le validateur du W3C vous enverra
bouler en cas de caractère "non-SGML" : ce n'est pas parce qu'on a
correctement détecté un codage de caractères, que celui-ci sera toujours
valide/bien employé...


Oui, absolument.

--
Olivier Miakinen
Troll du plus sage chez les conviviaux : le nouveau venu, avec
son clan, s'infiltre dans les groupes de nouvelles. (3 c.)

1 2