Supprimer les accents
des caractères accentués

Voilà un grand classique pour nous autres peuples de caractères : comment supprimer les accents des caractères accentués de notre sublime langue en utilisant PHP ? Mais avant de répondre à cette question, une autre se forme, insidieuse : pourquoi supprimer les accents des caractères accentués ? Voici quelques exemples envisageables :

  • Transformer une chaine pour qu'elle soit plus lisible dans une URL  : "severite" au lieu de "s%C3%A9v%C3%A9rit%C3%A9"
  • Transformer une chaine pour obtenir un nom de fichier propre
  • Pouvoir enfin ordonner les clés accentuées de nos tableaux associatifs PHP et ne plus retrouver « événement » après « zéro » !

Solution toute nulle

C'est ce dernier exemple qui m'a conduit à rechercher une solution viable. En effet, malgré tous les efforts de Google je n'ai réussi à trouver que des exemples utilisant des remplacements de caractères du style :

<?php

$str = strtr($str'ÁÀÂÄÃÅÇÉÈÊËÍÏÎÌÑÓÒÔÖÕÚÙÛÜÝ''AAAAAACEEEEEIIIINOOOOOUUUUY');
$str = strtr($str'áàâäãåçéèêëíìîïñóòôöõúùûüýÿ''aaaaaaceeeeiiiinooooouuuuyy');

Évidement, ça a l'air sexy et simple, mais si comme moi vous travaillez en utf-8, les caractères accentués sont bien souvent encodés avec plus de 8bits (un caractère en ASCII), mais jusqu'à 32bits. Ainsi, les techniques basées sur une substitution de caractères sont totalement obsolètes parce qu'elles produisent des résultats erronés. C'est triste, mais c'est vrai.

Comment faire alors ? Sommes-nous condamnés par des siècles d'histoire ?

Solution qui pourrait être géniale

Parce que, comme moi, vous dévorez la documentation de PHP chaque soir avant de vous coucher, vous avez peut-être remarqué la fonction iconv() et vous pensez, comme j'ai pu le faire, que c'est la solution parfaite pour notre affaire… si seulement. La fonction iconv() est donc sensée supporter la translittération, mais il semblerait que le résultat soit très variable d'un système à l'autre. En effet, pour la même version de PHP voici les résultats que j'obtiens à vouloir enlever les accents de « L'été est là »:

<?php

$str = "L'été est là";

iconv($charset'ASCII//TRANSLIT//IGNORE'$str);

// Linux : L'ete est la
// MacOSX et Windows : L''et'e est l`a

Alors voilà, c'est ridicule. Si on ne peut pas compter sur un résultat homogène, autant l'oublier tout de suite.

Solution pas mal

C'est en transformant d'anciens fichiers iso-8859-1 en utf-8 que la solution m'a sauté au visage tel un écureuil farceur : utiliser les entités échappées pour récupérer le caractère non accentué. En effet, "é" une fois échappé donne "&eacute" et "É" donne "&Eacute". Ne reste plus alors qu'à gérer les cas particuliers comme la cédille ou les ligatures, et le tour est joué. Ainsi, on utilise htmlentities() pour échapper les caractères exotiques puis on remplace ces expressions échappées grâce à de savantes expressions rationnelles :

<?php

function wd_remove_accents($str$charset='utf-8')
{
    $str = htmlentities($str, ENT_NOQUOTES, $charset);
    
    $str = preg_replace('#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#''\1'$str);
    $str = preg_replace('#&([A-za-z]{2})(?:lig);#''\1'$str)// pour les ligatures e.g. '&oelig;'
    $str = preg_replace('#&[^;]+;#'''$str)// supprime les autres caractères
    
    return $str;
}

Notez tout de même que je préfère supprimer les caractères échappés qui n'ont pas été traités. C'est pas l'idéal, mais ça me suffit…

Et maintenant, que vais-je faire ?

La fonction que je propose n'est évidement pas parfaite, l'idée de départ était de ne pas avoir à définir de tableau de conversion, mais en attendant une meilleure solution, ce petit bout de code fera bien l'affaire.

Dans un prochain billet nous verrons comment utiliser cette fonction pour ordonner les clés accentuées d'un tableau associatif. Que d'aventures !! À la prochaine !

Cette fonction, renommée ICanBoogie\remove_accents est aussi disponible dans le paquet icanboogie/common.

Laisser un commentaire

82 commentaires

Florent V.
Florent V.

Hello,

« mais si comme moi vous travaillez en utf-8, les caractères accentués sont bien souvent encodés avec plus qu'un seul caractère (jusqu'à trois en fait) »

Non, un caractère est un caractère et pas potentiellement une suite de plusieurs caractères. Par contre, un caractère peut être écrit avec plusieurs octets. Suivant les caractères, cela va de un à quatre (et non pas trois) pour l'UTF-8.

Attention donc à ne pas confondre octets et caractères. ;)

Olivier
Olivier

Tu fais bien de préciser cela Florent. J'ai préféré – à tord – parler de « caractères » plutôt que de « bits » parce que tout le monde n'a pas fait de l'assembleur (680×0 pour moi) et que le PHP est souvent un premier langage de programmation.

J'ai corrigé ces erreurs, je ne sais pas ce qui m'a prit.
Vulgarisation quand tu nous tiens :-)

bibi
bibi

Merci beaucoup pour ton petit bout de code. J'avais le même problème que toi et ça m'a bien aidé! Ton site est vraiment très intéressant on y apprend pleins de choses continue! ^^

6sko59
6sko59

Salut, Je tiens juste à te remercier. Ta fonction est super , elle m'a bien dépanné!!

6sko59

Maxime
Maxime

Thanks man,

comme quoi des fois à 2h du mat on trouve du bon sur le net …

K
K

À moins d'avoir à utiliser des encodages extra (qui pour la plupart ne sont pas gérés par htmlentities [cf. la doc]), il est conseillé d'utiliser les fonctions natives strtr / str_replace couplées avec utf8_encode/utf8_decode – encore une fois dans le cas où l'on se limite aux encodages utf-8 et latin1 (ce qui est d'ailleurs est le cas dans 99% des cas).

En effet, les expressions régulières sont bien trop gourmandes par rapport à strtr et encore plus par rapport à str_replace.

Si on passe par strtr il est préférable d'utiliser la forme avec un tableau : str( $str, array( 'à' => 'a' , 'é' => 'e' , etc. ); ce qui évite quelques soucis.

Dans le cas où l'on a effectivement besoin d'encodage « extra », par exemple lorsque l'on travaille sur un site japonais utilisant un encodage comme le EUC-JP, on a pas vraiment le choix que de passer par la méthode htmlentities ou autres méthodes plus complexes encore.

Néanmoins, je me permets une petite remarque, il est plus avantageux de trier les éléments « conditionels » dans une expression régulière :

(?:acute|cedil|circ|grave|ring|tilde|uml)

et non :

(?:uml|circ|tilde|acute|grave|cedil|ring)

En effet, la première version permet un gain de performance (même si certains appuient qu'elle est inutile dans le cadre d'une utilisation simple).

Dans tous les cas, tous ces problèmes seront réglés avec l'arrivée de PHP 6.

Il n'y a plus qu'à attendre…

Olivier
Olivier

Merci pour ta contribution monsieur K. mais comme tu peux t'en douter, je ne partage pas vraiment ton avis.

D'abord au sujet de strtr(). Alors oui, on peut s'amuser à recopier la centaine de caractères à traduire, en espérant ne pas en oublier. Après une heure de remplissage on obtient surement une fonction pratique.

MAIS.

  1. Il en faut deux versions (ou plus) : une pour traduire les chaines utf-8 (à placer dans un fichier en utf-8), et une pour traduire les chaines iso-8859-1 (à placer dans un fichier iso-8859-1)…
  2. On a plus la chance de tomber sur un caractère non supporté qu'avec ma fonction (qui vire tout ce qui ne lui plait pas dans la dernière phase).
  3. Impossible d'utiliser la même fonction pour supprimer les accents de chaines aux encodages différents. Ce qui est un jeu d'enfant avec ma fonction puisqu'il suffit de lui indiquer l'encodage source.

Ensuite, cette fonction ne fait que ce qu'elle dit : supprimer les accents des caractères. Ce n'est donc pas une très bonne idée de lui donner une chaine en EUC-J (ou Big5 pour ne pas faire de jaloux).

Quand à l'arrivée de PHP6, cela ne changera rien au schmilblick. Ce n'est pas parce qu'il travaille en utf-8 que l'on aura plus besoin de supprimer des accents de temps à autre (pour les noms de fichiers par exemple).

Bref, je conserve ma jolie fonction qui ne fait que quelques lignes et que je trouve si pratique (et jolie).

Je te remercie pour le conseil d'ordonnancement du masque conditionnel. Si ça peut faire gagner quelques micro secondes ;-)

Evan
Evan

Bonjour,

je pense aussi que ta solution est trop compliquée et bien trop gourmande. De plus elle est incomplète et suppose que l'encodage est iso-8859-1, ça ne va pas.

La solution complète et la plus rapide est une détection du type d'encodage (mb_detect_string), puis une conversion (iconv), puis un str_replace pour finir.

Pour finir, tu cites l'intégralité des accents des langues à alphabet latin : ÁÀÂÄÃÅÇÉÈÊËÍÏÎÌÑÓÒÔÖÕÚÙÛÜÝáàâäãåçéèêëíìîïñóòôöõúùûüýÿ. C'est tout, il n'yen a pas d'autres. Cette solution est donc complète, je ne comprend pas pourquoi tu parles de « en espérant ne pas oublier de caractère ».

Bonne chance

KissGround
KissGround

Super ! Pour ma part, elle me convient pleinement. L'on peut dire que tu as l'exclu… J'ai eu beau chercher, il n'y a rien de mieux.

KissGround ;)

madoxav
madoxav

Waouh! Un grand merci, après deux bonnes heures à batailler, j'ai enfin trouvé ce qu'il me fallait ;) bravo encore et bonne continuation!

jerko
jerko

merci, c'est effectivement mieux que le str() tout nu.

mais c'est lourd en CPU, c'est clairement pas optimisé … pourtant j'ai pas trouvé mieux pour l'instant, la solution d'Evan ne marche pas trop avec PHP4 + UTF8, je ne sais pas pourquoi …

Tib
Tib

Bonne astuce le htmlentities ;)

Intégré sur mon site, merci pour ta fonction

Snoo
Snoo

Bonjour, je travaille en utf-8. Voici une proposition de fonction a enregistrer en ISO-8859-1 (important):

<?php

function removeaccent($string)
{
    $string = utf8_decode($string);
    $string = strtr($string,    'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ',
                                'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY');
    $string = utf8_encode($string);                 
    return $string;
};
Kris
Kris

Bonjour,

Travaillant actuellement sur un nouveau site orienté game online, j'essaie de respecter les standards et de le faire en Oo (xhtml, css2, php5, mysql5).

Suite à diverse lecture et une mise en place d'une externalisation de la langue du code, j'en suis venu à me dire que pour aller au bout, il fallait tout passer en UTF-8. J'ai donc tout converti (base de données, fichiers, entête HTTP, fonction php (mb_)). Seul problème la version OterAccents que j'avais récupérer et que tu cites qui ne fonctionne plus bien évidemment.

Je te remercie donc pour cette fonction. Je n'ai trouvé que celle-ci en passant par google et encore parce que tu avais posté dans un billet sur un site.

Par contre, je salue la fonction de Snoo sur laquelle j'étais plus ou moins partie avant de chercher une solution « toute faite ». Mon seul problème c'est que je ne l'avais pas enregistré sous la forme ISO-8859-1 d'ou le fait que cela ne fonctionnait pas. En le mettant effectivement dans un fichier à part en ISO-8859-1, cela fonctionne parfaitement.

Merci donc à tous les deux pour votre précieuse aide :)

Kris

Fran6_yo
Fran6_yo

Merci beaucoup pour cette fonction, et c'est hallucinant que tout ce qu'on trouve sur le net soit la solution toute nulle.

:)

Thomas
Thomas

Bonjour,

Merci pour votre fonction, j'utilisais la fonction « toute nulle » mais là, j'ai bloqué avec l'utf8. Elle fonctionne très bien :)

Bonne continuation!

Lo
Lo

Merci bien pour ta fonction qui m'a sauvé la vie sur un projet encore encodé en ISO-8859-1…

Nico
Nico

Du bon boulot cette fonction, ça fait deux heures que je me prends la tête pour solutionner ce genre de problème. Merci !!!!

R.
R.

Bonjour,

merci pour cette fonction, qui m'a été très utile !

lor3m
lor3m

Excellente fonction, marche à la perfection, fini les strtr tout nul !! Merci bien.

cyberbobjr
cyberbobjr

Salut, c'est excellent ! la seule solution viable que j'ai trouvé sur le net. Bravo tu es un champion ! :)

Ham's
Ham's

Hello,

J'ai lu attentivement cet article sympa ainsi que tous les commentaires, cependant, je n'ai pas trouvé de réponse à ma petite question :

Qu'en est t-il des caractères encore plus exotiques ? En effet, je souhaiterais par exemple remplacer des caractères croates comme le « Š » par un « S » simple  !

Le fameux : $txt = str_replace(« Š », « s »,$txt); ne fonctionne pas malheureusement…

Si quelqu'un pourrait m'éclairer…

Merci !:)

blueeyes
blueeyes

un seul mot, merci.

Après plusieurs heures de galère à ne pas comprendre pourquoi les exemples trouvés sur le net ne fonctionnaient pas, enfin une solution.

Je vais pouvoir continuer mon développement.

Very good

IllusionPerdu
IllusionPerdu

Salut et pourquoi ne pas utiliser une fonction de se style :

<?php

function NoAccentFeed($text$EncIn = 'CP1252')
{
    return iconv($EncIn'ASCII//TRANSLIT//IGNORE'$text);
}
Olivier
Olivier

Salut IllusionPerdu,

J'avais déjà essayé d'utiliser iconv(), mais cet imbécile produit des résultats très différents d'un système à l'autre même pour des versions de PHP identiques. J'ai ajouté une section à mon article qui illustre cela : « Solution qui pourrait être géniale ».

Merci pour ta contribution.

David Anseaume
David Anseaume

C'est parce que iconv() est soumis au réglage de localisation de la machine, en l'occurrence le paramêtre LC_CTYPE , et donc précéder iconv() par :

setlocale(LC_CTYPE, 'fr_FR.UTF-8');

Clem
Clem

Ça dépend avec quel lib est compiler iconv si c'est glibc (sous debian par ex) ont peux oublier, par contre si c'est sous libiconv ça dépendra de la version

Olivier
Olivier

Comme le dit Clem, tout dépend de la bibliothèque utilisée par PHP. Pour cette raison, c'est pour moi une fonction à oublier, le temps que l'équipe de PHP trouve une solution consistante.

Clem
Clem

Ce qui serait envisageable c'est l'implémentation de la class Transliterator d'ICU (ext intl sous PHP). http://userguide.icu-project.org/transforms/general

Clem
Clem

J'ai fais la demande pour l'ajout de Transliterator c'était visiblement en cours, la personne qui s'en occupe l'a déposé dans le trunk ;)

Olivier
Olivier

Salut Clem,

En voilà une bonne nouvelle ! En espérant une implémentation uniforme cette fois… Tu aurais un lien pour suivre ces travaux ? sur news.php.net peut-être ?

clem
clem
clem
clem

j'ai tester pour le moment ça marche bien

<?php

$myTrans = Transliterator::create('NFD; [:Nonspacing Mark:] Remove; NFC');
    echo $myTrans->transliterate('àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ');
    //aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY
Olivier
Olivier

C'est plutôt une bonne nouvelle. Par contre, j'aurais préféré une méthode statique pour ne pas avoir à créer un objet. Je n'aurais plus qu'à modifier ma fonction pour utiliser une instance unique.

Clem
Clem

pas de problème intl propose toujours les deux (comme pour mysqli)

$myTrans = transliterator_create('NFD; [:Nonspacing Mark:] Remove; NFC'); echo transliterator_transliterate($myTrans, 'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ'); //aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY

l'avantage c'est qu'on peux virer les accents sans bidouille, mais le iconv (avec libiconv) le tranlit est pas mal non plus un © sera transformé en ©, un € en EUR. le tranliterator, le faut aussi pour la langue et par exemple :

echo Transliterator::create('any-latin')->transliterate('ナルト'); //naruto

ca veux dire que n'importes quelles types d'écritures peux être transformées en ASCII

Keul
Keul

ma solution (l'encodage du fichier doit être le même que celui de $txt) :

//conversion en minuscules
$txt=mb_strtolower($txt, 'UTF-8');

//suppression des accents
$search =explode(',','á,à,â,ä,ã,å,ç,é,è,ê,ë,í,ì,î,ï,ñ,ó,ò,ô,ö,õ,ú,ù,û,ü,ý,ÿ');
$replace=explode(',','a,a,a,a,a,a,c,e,e,e,e,i,i,i,i,n,o,o,o,o,o,u,u,u,u,y,y');
$txt=  str_replace($search,$replace,$txt);

//suppression des autres caractères (Pour des noms de fichiers par exemple)
$txt=  preg_replace('#[^a-zA-Z0-9\-\._]#', '_', $txt);
Clem
Clem

avec ça tu risques de te retrouver avec des fichiers type : _______.txt

Romain
Romain

Bonsoir,

Merci pour ce très bon article. Je vois que je suis loin d'être le seul à avoir rencontré ce problème !

Très bonne solution, qui répond parfaitement à mon besoin.

Continuez comme ça !

karnabal webmaster
karnabal webmaster

C'est à ce jour la meilleure solution que j'ai trouvée en termes de remplacement de caractères. Super pratique ! Merci !

Olivier
Olivier

Merci Yannick, j'ai corrigé ma conclusion.

Yannick K.
Yannick K.

Merci pour les solutions proposées ! Cependant la fonction mb_strreplace() dont vous faites allusion n'existe pas.

Olivier
Olivier

Tu peux toujours remplacer la ligne qui « supprime les autres caractères » par un html_entity_decode() pour restaurer les caractères échappés.

Cela dit, si tu utilise la fonction pour enlever les accents de tes URL, utilise plutôt la fonction http_build_query() pour construire ton URL et supprimer les accents sur les parties qui t'intéresse :

<?php

$url = 'monsite/index.php?' + http_build_query
(
    array
    (
        'user' => wd_remove_accents('élève'),
        'tome' => 36,
        'page' => 45
    )
);

N'oublie pas d'échapper ton URL avec htmlentities() si tu l'insére dans du code HTML.

Julien de Prabère
Julien de Prabère

Merci pour ces échanges enrichissants sur une proposition intéressante…

Toutefois, une difficulté subsiste, la suppression des esperluettes dans les adresses ! À titre d'exemple l'adresse :

« monsite/index.php?user=élève&tome=36&page=45 »; devient « monsite/index.php?user=élèvetome=36page=45 »;

Eric
Eric

Merci, tu viens tout simplement de me sauver la vie !

Chloé
Chloé

Merci !!!

Depuis le temps que je jonglais avec mes vieilles fonctions qui ne marchaient pas une fois sur deux selon l'encodage.

In my tools.php ;)

Creation graphique Grenoble
Creation graphique Grenoble

C'est super utile quand on a des problèmes d'encodage, merci :)

Landru
Landru

Merci pour l'article. La solution fonctionne à merveille !! Bravo pour le partage

Benjamin
Benjamin

Merci, une fonction qui m'enlève une belle épine du pied!

Mysterty
Mysterty

Ingénieuse solution…

Mais personnellement, je préfère iconv, même si ça demande de paramétrer le serveur, et Transliterator est génial (même si j'ai pas encore eu l'occasion de l'utiliser).

Bref, pour ma part de toute façon, je passe par Doctrine, ce qui me permet d'avoir : Doctrine_Inflector::urlize() ou simplement Doctrine_Inflector::unaccent(). Je n'ai pas testé les performances, mais au niveau confort de développement, j'y gagne ! :)

Olivier
Olivier

D'après ce que je vois, ça revient à utiliser la solution « toute nulle », même s'il s'agit d'une solution deluxe. Comment ça se passe maintenant avec Symfony2, le code se trouve toujours dans l'ORM ?

J'aurais bien aimé tester Normalizer::normalize() mais il n'est pas disponible sur mon installation Ubuntu, je me demande s'il ne manque pas un truc à installer puisque j'ai PHP5.3.<je_ne_sais_quoi>.

Mysterty
Mysterty

Je n'ai pas encore testé Symfony 2, et je n'ai pas non plus Normalizer (qui a encore l'air d'être une fonction forte intéressante).

En effet, Doctrine utilise la solution du stringstr, mais gère tous les cas, en UTF-8 ou en ISO, version « de luxe » comme tu dis. ^^

magickriss
magickriss

On dira ce qu'on veut mais pour moi aussi c'est à ce jour la meilleure solution que j'ai trouvé en termes de remplacement de caractères. Merci milles fois!

Philippe
Philippe

Fonction essayée et adoptée !

Elle fonctionne du premier coup dans l' environnement suivant :

UTF 8 PHP 5

Merci beaucoup !

Philippe

José
José

hello,

Merci pour ta solution efficace qui supprime enfin les accents.

C'est réellement la meilleure que j'ai trouvé sur le web!

Glauber Rocha
Glauber Rocha

Bonjour, Je vous indique également la solution « gagnante » proposée sur ce thread de Stackoverflow.com : http://stackoverflow.com/questions/3542818 Elle est un peu longue mais (paraît-il) utilisée par Wordpress.

Carles
Carles

Merci Glauber Rocha, en ayant tout testé, on dirait que c'est celle qui est la plus précise ;)

miaoulafrite
miaoulafrite

salut en fait, strtr fonctionne à condition de l'utiliser avec d'autres arguments plutôt que de lui donner $from et $to, utilisez $replace_pairs http://php.net/manual/fr/function.strtr.php

exemple: $translit = array('Á'=>'A','À'=>'A','Â'=>'A','Ä'=>'A','Ã'=>'A','Å'=>'A','Ç'=>'C','É'=>'E','È'=>'E','Ê'=>'E','Ë'=>'E','Í'=>'I','Ï'=>'I','Î'=>'I','Ì'=>'I','Ñ'=>'N','Ó'=>'O','Ò'=>'O','Ô'=>'O','Ö'=>'O','Õ'=>'O','Ú'=>'U','Ù'=>'U','Û'=>'U','Ü'=>'U','Ý'=>'Y','á'=>'a','à'=>'a','â'=>'a','ä'=>'a','ã'=>'a','å'=>'a','ç'=>'c','é'=>'e','è'=>'e','ê'=>'e','ë'=>'e','í'=>'i','ì'=>'i','î'=>'i','ï'=>'i','ñ'=>'n','ó'=>'o','ò'=>'o','ô'=>'o','ö'=>'o','õ'=>'o','ú'=>'u','ù'=>'u','û'=>'u','ü'=>'u','ý'=>'y','ÿ'=>'y'); $string= strstr($string, $translit);

enlèvera tous les accents, quelque soit l'encodage…

Olivier
Olivier

Et non justement.

Si ta fonction se trouve dans un fichier encodé en iso-8859-1 alors elle ne fonctionnement qu'avec des chaines de caractères encodées en iso-8859-1. De la même façon, si ta fonction se trouve dans un fichier encodé en utf8 elle ne fonctionnera qu'avec des chaines de caractères elles aussi encodées en utf8.

miaoulafrite
miaoulafrite

antant pour moi dans mon cas tout est en UTF8

Ajorr
Ajorr

Un grand merci à l'auteur de ce billet. Ton script ma bien dépanner.  ;)

Vivien
Vivien

Excellente fonction, marche à la perfection, fini les strtr !! Merci bien pour l'astuce :)

Seyart
Seyart

Merci pour cet article. Cela m'a bien aidé pour proposer des URLs « propres ».

Cyril
Cyril

Ben moi en production j'utilise une fonction de ce style.

<?php

function string_to_filename($chaine)
{
    $recherche = array('#[àâäÂÄ]#i''#[éèêëÊË]#i''#[îïÎÏ]#i''#[ôöÔÖ]#i''#[ûùüÛÜ]#i''#[ç]#i''#[ ]#i''#[^a-zA-Z0-9_]#');
    $remplacement = array('a''e''i''o''u''c''_''_');
    return preg_replace($recherche$remplacement$chaine);
}

Le dernier regex sert à remplacer tout caractère non alphanumérique par un underscore.

Olivier
Olivier

Salut Cyril, je te renvoi à mon commentaire du 2 février

cyril
cyril

Salut Olivier. Merci, mon message à une meilleure tête comme ça ^^. Effectivement je viens de lire ton message, du 2 Février, et du coup je me demande par curiosité, dans quelle cas tu dois transformer une chaîne qui n'est pas de l'encodage que tu utilise dans ton application web parce que je vois que je passe du temps à faire super gaf au encodage utilisé de partout et la seule fois où j'ai eu un soucis c'est a cause des transactions à la base en utf8 et je faisait une extraction de cvs pour remplir ma bdd avec un fichier depuis un serveur sous windows et il a fallu que je teste l'encodage et dire que c'est c'est pas utf8, on convertit de Windows 1252 à UTF8. parce qu'après test je n'ai ce soucis que sur serveur windows. Du coup si t'as des exemples de la limite de ma fonction je suis à fond preneur. Très curieux et désireux de comprendre. Merci d'avance Cordialement Cyril.

Olivier
Olivier

@cyril: Ta fonction est tout a fait valable tant que ta source est encodée dans le même jeu de caractères que le fichier PHP qui contient ta fonction. Si tu développes toute ton application pour travailler en utf-8 tu ne rencontreras pas de problèmes jusqu'à ce que tu doives manipuler des données externes dont tu ne contrôles pas l'encodage, comme ce fichier CSV dont tu parles. Dans ce cas, il faudra que tu transcodes les données de ton fichier CSV dans le même jeu de caractères que celui du fichier où est définie ta fonction.

Si tu utilises la fonction que je propose tu n'auras pas besoin de transcoder la source, mais simplement de préciser son encodage.

Le problème principal que je vois dans ces fonctions qui utilisent des caractères accentués c'est que leur code est copié/collé et parfois l'encodage du fichier de destination n'est pas adéquat et la fonction produit des résultats erronés. Par exemple si tu copies le code de la fonction toute nulle dans un fichier encodé en utf-8 tu risque d'avoir quelques surprises, parce qu'elle établie une correspondance 8bit/8bit alors que les caractères accentués utilisent plutôt 16bit en utf-8, voire plus.

cyril
cyril

@Olivier: Effectivement, je fais toujours attention à ce que mes sources soit dans le même encodage que l'interface de l'application, que les transactions à la base etc… J'avoues que des fonctions comme la mienne tu dois en trouver un paquet qui ressemblent, faut dire aussi qu'il n'y a pas non plus énormément de façon de faire ce qu'elle fait. Mais je te promet que je l'ai écrite comme un grand ^^ Du coup tu me rassures pour mon cas perso où les soucis que j'aurais sont ceux que j'ai déjà rencontrés à cause de fichiers externes parce que comme je le disait à mon premier post, cette fonction est dans une application production. Mais du coup ça me laisse à penser que ta solution si je l'ai bien comprise ne fonctionnerais pas pour mon cas puisque il faut connaître l'encodage du fichier. Chose d’ailleurs compliqué à déterminer grâce au contenu du fichier puisque la valeur d'un caractère peut exister en utf8 et être un autre caractère dans un autre encodage. En tout cas merci de ta réactivité et de tes réponses. Au plaisir….

Dim
Dim

Merci… Je cherchais quelque chose qui marche et grâce à vous, c'est bon. :)

Woolkaya
Woolkaya

Merci pour cette fonction qui m'est très utile :) Woolkaya

arrivedercho
arrivedercho

salut, moi j'ai conçu ma petite fonction cette nuité… l'avantage de celle-ci est qu'elle enlève seulement les accents, ne traite pas les signes de monnaie, dit le temps qu'elle met à s'éxécuter et renvoie les index qui changent (en php un caractère utf8 peut être interprété comme plus long que 1.

https://gist.github.com/4228184

Olivier
Olivier

Salut Patrick,

Est-ce que tu spécifies le type d'encodage que tu utilises ? Par défaut c'est utf-8 qui est utilisé :

<?php

echo wd_remove_accents("L'été est là"'iso-8859-1');
DESAUNAY
DESAUNAY

Bonjour,

Je trouve ce script sympa, mais je bute sur deux points: Le 'œ' ne se retraduit pas en en 'oe' dans mon cas (codage de page en ISO-8859-1) Il reste à œ.

Deuxièmement, j'avais espéré que en mettant le paramètre double_encode de htmlentities à false, le logiciel aurait su passer outre des codages en &eacute. Manque de bol, il les recode. Ca fait: Ça va, mon cœur é à éviter et adoré? (le 'é' affiché est en fait un '&eacute') qui devient Ca va, mon cœur eacute a eviter et adore?

Je pense m'en sortir en bricolant, mais si quelqu'un a des idées, merci d'avance.

Patrick

Jeremie
Jeremie

Merci pour cette fonction bien utile.

DESAUNAY
DESAUNAY

Bonjour,

J'ai fait des tests avec deux encodages, utf et ISO 8859 machin, en changeant la déclaration dans la page. Même problème. En fait, en appliquant le principe « ya bien une fonction PHP qui fait ça » j'ai pu imprimer la liste des caractères transformés par htmlentities. Et le oe collés n'est pas dans cette liste. Voila. Donc j'ai rajouté une ligne de regx machin qui remplace « en dur ». Info pour ceux qui rameraient encore sur ce problème. (je ne veux pas faire le troll, mais ça semble être un point en faveur des fonctions regex codées en dur. Au moins, on voit les caractères traités)

Reste pour ma curiosité la question de la fonction qui ne devrait pas double-encoder.

Merci Patrick

Olivier
Olivier

C'est vraiment bizarre parce qu'à l'époque ou j'ai écris cette fonction j'étais encore sous Windows avec WAMP (pas Winamp héhé)… Les caractères sont bien présents, comme le montre cet extrait :

  'þ' => string '&thorn;' (length=7)
  'ÿ' => string '&yuml;' (length=6)
  'Œ' => string '&OElig;' (length=7)
  'œ' => string '&oelig;' (length=7)
  'Š' => string '&Scaron;' (length=8)
  'š' => string '&scaron;' (length=8)
  'Ÿ' => string '&Yuml;' (length=6)

Est-ce que tu as joué avec les options pour voir s'il y avait plus de caractères ? Par exemple get_html_translation_table(HTML_ENTITIES, ENT_COMPAT | ENT_HTML5, 'utf-8').

J'en ai profité pour mettre à jour la fonction, qui supporte maintenant le caron e.g. « Š »

La fonction est à jour sur GitHub. J'ai aussi ajouté quelques tests.

DESAUNAY
DESAUNAY

N'étant pas un expert, j'ai juste testé la fonction de la même façon sur W(in)amp et sur OVH. Comme il y avait différence, ça m'a suffi. J'avais mis HTML_ENTITIES en paramètre. Pour info, la version Winamp est la 2.2. Je suppose que je ne suis pas à jour, mais elle me suffit en général.

Patrick

Olivier
Olivier

Il y a bien une entité pour « œ » il s'agit de « &oelig; », comme tu peux le voir ici:

http://www.fileformat.info/info/unicode/char/153/index.htm

Pour « Œ » il s'agit bien sûr de « &OElig; », comme tu peux le voir ici:

http://www.fileformat.info/info/unicode/char/0152/index.htm

Cela fonctionne parfaitement avec PHP, essaie donc le code suivant:

<?php

echo htmlspecialchars(htmlentities("\xC5\x93uf", ENT_COMPAT, 'utf-8'), ENT_COMPAT, 'utf-8');

Tu peux tester en ligne ici: http://writecodeonline.com/php/

PS: La séquence « \xC5\x93 » représente « œ » en UTF-8. C'est juste pour l'exemple en ligne.

Desaunay
Desaunay

Bonjour,

Ça, c'est le fonctionnement normal. Ça me rassure. Mais sur mon implémentation (winanmp), le « œ » n'est pas présent. Pour info, si j'imprime get_html_translation_table(HTML_ENTITIES), ça donne ça:

Array ( [ ] =>   [¡] => ¡ [¢] => ¢ [£] => £ [¤] => ¤ [¥] => ¥ [¦] => ¦ [§] => § [¨] => ¨ [©] => © [ª] => ª [«] => « [¬] => ¬ [­] => ­ [®] => ® [¯] => ¯ [°] => ° [±] => ± [²] => ² [³] => ³ [´] => ´ [µ] => µ [¶] => ¶ [·] => · [¸] => ¸ [¹] => ¹ [º] => º [»] => » [¼] => ¼ [½] => ½ [¾] => ¾ [¿] => ¿ [À] => À [Á] => Á [Â] => Â [Ã] => Ã [Ä] => Ä [Å] => Å [Æ] => Æ [Ç] => Ç [È] => È [É] => É [Ê] => Ê [Ë] => Ë [Ì] => Ì [Í] => Í [Î] => Î [Ï] => Ï [Ð] => Ð [Ñ] => Ñ [Ò] => Ò [Ó] => Ó [Ô] => Ô [Õ] => Õ [Ö] => Ö [×] => × [Ø] => Ø [Ù] => Ù [Ú] => Ú [Û] => Û [Ü] => Ü [Ý] => Ý [Þ] => Þ [ß] => ß [à] => à [á] => á [â] => â [ã] => ã [ä] => ä [å] => å [æ] => æ [ç] => ç [è] => è [é] => é [ê] => ê [ë] => ë [ì] => ì [í] => í [î] => î [ï] => ï [ð] => ð [ñ] => ñ [ò] => ò [ó] => ó [ô] => ô [õ] => õ [ö] => ö [÷] => ÷ [ø] => ø [ù] => ù [ú] => ú [û] => û [ü] => ü [ý] => ý [þ] => þ [ÿ] => ÿ [&] => & ["] => " [<] => < [>] => > ) 

Du coup, ta remarque est bien intéressante. J'ai vérifié sur l'implémentation en ligne (chez OVH) et il y a beaucoup plus de caractères, dont le fameux 'OElig'. Je vais modifier mon script en enlevant cette ligne. Espérons que ça serve à d'autres gens de savoir que la version Winamp est tronquée.

Hourra! et merci.

Anand Selvadurai
Anand Selvadurai

You can give a try and test all unicode/utf-8 character processing in PHP using this link, www.writephponline.com

Tristan B
Tristan B

Merci beaucoup pour cette fonction, elle me dépanne bien ;)

Jesse
Jesse

Bonjour, Superbe article qui me sert beaucoup. Mais n'étant pas un spécialiste des REGEX, j'aimerais savoir comment effectuer ce retrait d'accent sur les caractères majuscules uniquement… Merci d'avance (J'ai quand même cherché avant de poster ici)

Jerome
Jerome

Bonjour et merci pour ce bout de code qui m'a sauvé.

Je ne connaissais pas le charset, j'ai donc mis ini_get(« default_charset ») Et ça a fonctionné.