Remplacer les caractères diacritiques en équivalents pas diacritiques.

laurrislaurris Membre
septembre 2008 modifié dans API AppKit #1
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.

Réponses

  • schlumschlum Membre
    13:55 modifié #2
    Tu veux plutôt dire passage de la forme NFD à  la forme NFC plutôt non ? Parce qu'il n'y a pas toujours un équivalent à  une composition de caractères diacritiques.

    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
  • laurrislaurris Membre
    13:55 modifié #3
    oula, si je comprends bien il existe du precomposed  unicode quand on tape la lettre à  sur un clavier mac fr par exemple et du decomposed unicode quand on tape ଠavec deux touches successives (modifier + i).
    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.
  • AliGatorAliGator Membre, Modérateur
    13:55 modifié #4
    Oui en fait c'est loin d'être simple.

    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
  • NoNo Membre
    13:55 modifié #5
    Tu as de la chance, car depuis 10.4, CFString intègre les API de ICU.
    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 :
    <br />{<br />&nbsp;  NSMutableString *cocoaStr;<br />&nbsp;  CFStringRef corestr;<br /><br />&nbsp;  // lecture <br />&nbsp;  cocoaStr=[[NSMutableString alloc] initWithContentsOfFile:@&quot;/texte.txt&quot; encoding:NSUTF8StringEncoding error:nil];<br /><br />&nbsp;  // cast du NSString* en CFStringRef (magie du tool-free-bridging)<br />&nbsp;  corestr=(CFStringRef)cocoaStr;<br /><br />&nbsp;  // converstion de la chaà®ne de départ&nbsp; en canonical-unicode<br />&nbsp;  // (ça permet de séparer les composants diacritiques des caractères de base)<br />&nbsp;  CFStringNormalize(corestr, kCFStringNormalizationFormD);<br /><br />&nbsp;  // application d&#39;une règle ICU à  la chaine canonisée: cette règle enlève les signes diacritiques<br />&nbsp;  CFStringTransform(corestr, NULL, CFSTR(&quot;[:Nonspacing Mark:] Remove&quot;), false);<br /><br />&nbsp;  // maintenant tous les caractères accentués sont devenus non-accentués.<br />&nbsp;  NSLog(@&quot;%@&quot;, cocoaStr);<br /><br />&nbsp;  [cocoaStr release];<br />}<br />
    

  • AliGatorAliGator Membre, Modérateur
    septembre 2008 modifié #6
    Ah sympa ça... Je connaissais pas les ICU, ça a l'air puissant :D

    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]" ?
  • NoNo Membre
    13:55 modifié #7
    dans 1222632916:

    1) ne pas utiliser simplement kCFStringTransformStripCombiningMarks comme paramètre de CFStringTransform directement, en fait ? (en plus ça reste ainsi compatible pré-10.4)

    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.

    dans 1222632916:

    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]" ?

    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.
  • schlumschlum Membre
    13:55 modifié #8
    Euh, vous avez compris qu'il souhaitait supprimer les accents vous dans la question ?  ???
  • NoNo Membre
    13:55 modifié #9
    dans 1222685043:

    Euh, vous avez compris qu'il souhaitait supprimer les accents vous dans la question ?  ???

    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 ?
  • schlumschlum Membre
    13:55 modifié #10
    dans 1222688175:

    dans 1222685043:

    Euh, vous avez compris qu'il souhaitait supprimer les accents vous dans la question ?  ???

    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 "à "
  • AliGatorAliGator Membre, Modérateur
    13:55 modifié #11
    dans 1222671684:

    dans 1222632916:

    1) ne pas utiliser simplement kCFStringTransformStripCombiningMarks comme paramètre de CFStringTransform directement, en fait ? (en plus ça reste ainsi compatible pré-10.4)

    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.

    dans 1222632916:

    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]" ?

    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.
    Arf :P D'autant que je mettais ça "juste au passage", mais à  l'origine je proposais ça car ça me semblait plus lisible d'utiliser une constante comme "kCFStringTransformStripCombiningMarks" que les ICU moins triviales, donc le coup du "en plus c'est compatible pré-10.4" c'était vraiment pur bonus ^^

    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 !
  • NoNo Membre
    13:55 modifié #12
    dans 1222689030:

    Euh, je ne lis pas ça comme ça du tout...
    Je lis ça comme remplacer "a`" par "à "

    C'est pas faux !
    Donc dans ce cas, une transformation ICU en "composed" devrait peut être suffire.
  • laurrislaurris Membre
    septembre 2008 modifié #13
    Merci à  tous pour vos réponses, et surtout à  ceux qui "cherchent la petite bête" parce du moment que c'est pertinent on apprend toujours en comparant différentes façons de résoudre un problème.

    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.
  • schlumschlum Membre
    13:55 modifié #14
    dans 1222692441:

    Merci à  tous pour vos réponses, et surtout à  ceux qui "cherchent la petite bête" parce du moment que c'est pertinent on apprend toujours en comparant différentes façons de résoudre un problème.

    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 !)
  • AliGatorAliGator Membre, Modérateur
    13:55 modifié #15
    dans 1222699365:
    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 !)
    Ben heu certes mais avec le CFStringTransform justement (et les ICU ou le kCFStringTransformStripCombiningMarks au choix) tout est fait tout seul justement... donc la solution est toute trouvée !
    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 ?
  • schlumschlum Membre
    13:55 modifié #16
    Si ce sont juste les diacritiques des alphabets européens qui sont visées, elles sont regroupées entre 0x300 et 0x36F aussi...
  • NoNo Membre
    13:55 modifié #17
    dans 1222757767:

    Si ce sont juste les diacritiques des alphabets européens qui sont visées, elles sont regroupées entre 0x300 et 0x36F aussi...

    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.
  • laurrislaurris Membre
    13:55 modifié #18
    Cocotron c'est cocoa multi-platforme , mais surtout pour windows. Et donc, tu vas me demander (si si je le sens): quelle différence avec GNUSptep ? Ben d'abord GNUStep ne gère pas windows, ensuite GNUstep a plein de dépendances qui ne permettent pas de deployer facilement une application cocoa sur une autre plate-forme que OSX.
    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)
  • AliGatorAliGator Membre, Modérateur
    décembre 2009 modifié #19
    Bonjour à  tous

    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 :
    NSString* str = [unChampTexte stringValue];<br />NSLog(@&quot;Texte d&#39;origine : %@&quot;,str);<br /><br />NSString* sansAccents = [str stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:[NSLocale currentLocale]];<br />NSLog(@&quot;Texte &#39;folded&#39; : %@&quot; , sansAccents);
    
    Et là ... miracle !
    log a écrit:
    Texte d'origine : Mais où peut-il être cet énergumène ?
    Texte 'folded' : Mais ou peut-il etre cet energumene ?


    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 :)
  • NoNo Membre
    13:55 modifié #20
    dans 1223128960:

    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" ?

    N'ayant pas 10.5, je ne peux utiliser cette méthode.
Connectez-vous ou Inscrivez-vous pour répondre.