Remplacer les caractères diacritiques en équivalents pas diacritiques.
laurris
Membre
Tout est dans le titre.
Ca a l'air simple mais je butte grave là -dessus. D'abord il n'y a pas de méthode cocoa toute faite. Je crois qu'il existe une fonction carbon mais je veux absolument l'éviter.
Ce qui ne marche pas :
dataUsingEncoding:allowLossyConversion:YES en convertissant de unicode vers ascii.
Parce que tous les caractères unicode, même non diacritiques, seront convertis en ascii.
Ce qui n'est pas très efficace:
replaceOccurenceOfString:withString: parce que les caractères diacritiques se trouvent dans la table unicode dans des ranges déterminés qui donnent 1 caractère équivalent. Donc autant tester sur des ranges plutôt que sur chaque caractère.
Problème: A ma connaissance il n'existe pas de méthode du genre replaceCharactersInSet:withString:
Donc je ne vois comme solution que de passer par une routine en C.
On aurait un array à deux dimensions avec d'un coté un range et de l'autre un int. Malheureusement je coince sur la façon de représenter un range en C et même sur la façon de passer d'un char à son équivalent numérique. C'est sûrement tout bête mais je ne trouve pas.
Donc je cherche:
- Soit une solution Foundation efficace (avec des ranges).
- Soit une routine en C pour remplacer un range unicode par un caractère unicode dans une chaà®ne.
A vot' bon coeur.
Ca a l'air simple mais je butte grave là -dessus. D'abord il n'y a pas de méthode cocoa toute faite. Je crois qu'il existe une fonction carbon mais je veux absolument l'éviter.
Ce qui ne marche pas :
dataUsingEncoding:allowLossyConversion:YES en convertissant de unicode vers ascii.
Parce que tous les caractères unicode, même non diacritiques, seront convertis en ascii.
Ce qui n'est pas très efficace:
replaceOccurenceOfString:withString: parce que les caractères diacritiques se trouvent dans la table unicode dans des ranges déterminés qui donnent 1 caractère équivalent. Donc autant tester sur des ranges plutôt que sur chaque caractère.
Problème: A ma connaissance il n'existe pas de méthode du genre replaceCharactersInSet:withString:
Donc je ne vois comme solution que de passer par une routine en C.
On aurait un array à deux dimensions avec d'un coté un range et de l'autre un int. Malheureusement je coince sur la façon de représenter un range en C et même sur la façon de passer d'un char à son équivalent numérique. C'est sûrement tout bête mais je ne trouve pas.
Donc je cherche:
- Soit une solution Foundation efficace (avec des ranges).
- Soit une routine en C pour remplacer un range unicode par un caractère unicode dans une chaà®ne.
A vot' bon coeur.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Oui, les fonctions sont en Carbon, mais je crois que depuis peu elles existent en Cocoa également !
http://developer.apple.com/qa/qa2001/qa1235.html
Je vais me contenter du precomposed pour l'instant (peut-être que pour le decomposed je pourrais juste virer le modifier ...).
Par contre je ne vois pas d'API cocoa pour ça, et de toute façon, si j'en trouve une il la faudrait "simple". Pour que ce soit plus clair, mon code est destiné à une implementation dans cocotron http://www.cocotron.org. Et dans cocotron il n'y a pas tout cocoa, en tous cas pas encore.
Pour l'instant, si je pouvais savoir comment transformer un code unicode octodecimal en cString (340=à ) et inversement, ça m'aiderait drôlement. Après je n'aurait plus qu'à construire la table de correspondance.
En Unicode, il y a plusieurs manières de faire une lettre accentuée : avec le glyphe caractère accentué précomposé (donc un seul caractère), ou en décomposant le glyphe en plusieurs caractères, le caractère de l'accent + le caractère non accentué. Ce qui permet d'ailleurs de créer des glyphes contenant plusieurs accents, un a avec un accent grave et un rond*...
Une solution serait en effet de forcer le passage à la forme unicode décomposée (NFD) puis de supprimer tous les caractères UTF8 correspondant à des diacritiques seules. Ainsi par exemple un "é" sera décomposé en "´"+"e" et ensuite tu peux facilement je pense supprimer le caractère diacritique "´" ainsi isolé... (mais ça revient au problème initial, il faudrait une méthode qui dise "supprime tous les caractères qui sont dans ce range de codepoint unicode... mais bon ça on peut s'en sortir avec une boucle sur les caractères je pense )
*il a un nom cet accent mais je ne m'en souviens plus :P
Or avec ICU, c'est très facile de supprimer les accents des caractères.
Le code ci dessous lit un fichier texte (dont le texte est en UTF8) et supprime tous les accents de ce texte :
Mais pourquoi :
1) ne pas utiliser simplement kCFStringTransformStripCombiningMarks comme paramètre de CFStringTransform directement, en fait ? (en plus ça reste ainsi compatible pré-10.4)
2) Ou sinon quitte à utiliser les ICU, pourquoi ne pas faire tout le travail par la transformation en utilisant "[tt]NFD; [:Nonspacing Mark:] Remove; NFC[/tt]" ?
Dans un autre post, je me suis fait rembarré quand j'ai mis le bout d'une idée de faire une appli encore compatible 10.4, alors avec ton "pré 10.4", c'est la guillotine que tu risques.
Que tu voyages en Renault, Peugeot, etc..., peu importe, l'important étant d'arriver à destination.
Alors cesse de te poser des questions ou de chercher une petite bête qui n'existe pas.
Tout est dans le titre du post :
"Remplacer les caractères diacritiques en équivalents pas diacritiques",
c'est à dire un "à " devient un "a", un "ç" un "c", etc...
Non ?
Euh, je ne lis pas ça comme ça du tout...
Je lis ça comme remplacer "a`" par "à "
Par contre heu je pense pas chercher la petite bête qui n'existe pas, je proposais juste une solution qui me semblais sinon plus simple du moins plus lisible et compréhensible (peu de monde connait les ICU et faut comprendre ce que ça fait, et en plus c'est une chaà®ne à taper et pas une constante, risque de fautes, alors qu'une simple constante Apple au moins c'est propre et clair surtout vu le nom qui est explicite).
Je dis pas que c'est mieux ou moins bien ou quoi, je dis juste que ça me semble être une alternative (rendant le code plus lisible au demeurant, du moins de mon point de vue) et je me demandais pourquoi tu avais proposé les ICU plutôt que ça du coup : si je posais la question c'était que je me disais qu'il y a peut-être une raison, un vice caché, une subtilité... donc pas la peine de me rembarrer comme ça, hein !
C'est pas faux !
Donc dans ce cas, une transformation ICU en "composed" devrait peut être suffire.
Pour répondre à Schlum, diacritique != decomposed unicode , ou alors j'ai pas compris. Donc je voudrais transformer les decomposed ET les precomposed en sans diacritiques.
"`a" -> "a"
"à " -> "a"
Je vais demander au chef de cocotron (http://www.cocotron.org) s'il peut supporter ICU , ça me parait la meilleure option.
Ah d'accord, donc c'est No qui avait raison
Et là oui, c'est beaucoup plus compliqué... Il faut passé en décomposed et supprimer les caractères diacritiques (sachant qu'il y en a un peu partout dans l'unicode !)
D'ailleurs si tu vas sur le site d'aide pour les transformations ICU, le premier exemple donné est précisément la transformation ICU pour supprimer les diacritiques... donc s'ils le donnent comme exemple on a peu de chance de se tromper et de passer à côté d'une subtilité, c'est que c'est pile poil ce qui est recherché par laurris, non ?
Qui sera le plus rapide, une ch'tite fonction C qui élimine les diacritiques entre 0x300 et 0x36F, ou la règle ICU ?
C'est clair, C sera toujours devant.
Par contre ICU sera peut-être plus "respectueux" de certaines particularités.
A Laurris de décider.
Soit dit en passant, je ne comprends pas trop ce qu'est/sert Cocotron.
Cocotron peut aussi être intégré à Xcode, je crois qu'il existe un SDK.
Et surtout la licence LGPL permet de réutiliser le code pour n'importe quel usage. Par exemple, moi je m'en suis servi pour implémenter NSPredicate dans l'iPhone , après avoir bouché quelques trous. (Et j'ai aussi porté NSPredicate vers cappuccino, la nouvelle API web que j'ai découverte ici-même en lisant un des messages, mais c'est une autre histoire)
Je relance ce thread car je viens de faire une découverte par hasard : en lisant la doc de NSString, je vois une méthode "[tt]stringByFoldingWithOptions:locale:[/tt]"... Je me dis "tiens, mais je la connais pas cette méthode, elle fait quoi, ils entendent quoi par "folding" ?
Et là je lis... je vois entre autre les valeurs de l'enum [tt]NSStringCompareOptions[/tt] qui peuvent être utilisées.. dont [tt]NSDiacriticInsensitiveSearch[/tt]... là ça commence à tiquer...
Et puis je teste : Et là ... miracle !
C'est quand même plus court et lisible que les précédentes versions proposées, non ? En un appel à une méthode toute prête de Cocoa, on enlève toutes les diacritiques pour les remplacer par les non diacritiques ! Je trouve ça magique
N'ayant pas 10.5, je ne peux utiliser cette méthode.