Question

J'ai un problème avec une chaîne en C ++ qui contient plusieurs mots en espagnol. Cela signifie que j'ai beaucoup de mots avec des accents et des tildes. Je veux les remplacer pour leurs homologues non accentués. Exemple: je souhaite remplacer ce mot: " había " pour habia. J'ai essayé de le remplacer directement, mais avec la méthode replace de la classe string, mais cela ne fonctionnait pas.

J'utilise ce code:

for (it= dictionary.begin(); it != dictionary.end(); it++)
{
    strMine=(it->first);
    found=toReplace.find_first_of(strMine);
    while (found!=std::string::npos)
    {
        strAux=(it->second);
        toReplace.erase(found,strMine.length());
        toReplace.insert(found,strAux);
        found=toReplace.find_first_of(strMine,found+1);
    }
}

dictionnaire est une carte comme celle-ci (avec plus d'entrées):

dictionary.insert ( std::pair<std::string,std::string>("á","a") );
dictionary.insert ( std::pair<std::string,std::string>("é","e") );
dictionary.insert ( std::pair<std::string,std::string>("í","i") );
dictionary.insert ( std::pair<std::string,std::string>("ó","o") );
dictionary.insert ( std::pair<std::string,std::string>("ú","u") );
dictionary.insert ( std::pair<std::string,std::string>("ñ","n") );

et toReplace est une chaîne:

std::string toReplace="á-é-í-ó-ú-ñ-á-é-í-ó-ú-ñ";

Je dois évidemment manquer quelque chose. Je ne peux pas comprendre. Existe-t-il une bibliothèque que je peux utiliser?.

Merci,

Était-ce utile?

La solution

Tout d’abord, c’est une très mauvaise idée: vous brouillez la langue de quelqu'un en enlevant des lettres. Bien que les points supplémentaires dans des mots tels que «naïf» semblent superflus aux personnes ne parlant que l'anglais, il existe littéralement des milliers de systèmes d'écriture dans le monde dans lesquels de telles distinctions sont très importantes. Ecrire un logiciel pour mutiler le discours de quelqu'un vous met carrément du mauvais côté de la tension entre utiliser des ordinateurs comme moyen d'élargir le domaine de l'expression humaine par rapport aux outils de l'oppression.

Quelle est la raison pour laquelle vous essayez de faire cela? Est-ce qu'il y a quelque chose de plus grave qui finit par s'étouffer? Beaucoup de gens aimeraient vous aider à résoudre ce problème.

Cela dit, libicu peut le faire pour vous. Ouvrez la la démo de transformation ; copiez et collez votre texte en espagnol dans la case «Entrée»; entrez

NFD; [:M:] remove; NFC

comme "Composé 1" et cliquez sur transformer.

(Avec l'aide de la diapositive 9 de les transformations Unicode en mode ICU . Les diapositives 29 à 30 montrent comment utiliser l'API.)

Autres conseils

Je ne suis pas d'accord avec le texte actuellement "approuvé". réponse. La question est parfaitement logique lorsque vous indexez du texte. Comme pour la recherche insensible à la casse, la recherche insensible à l'accent est une bonne idée. "na" # 239; ve " correspond à " Na & # 239; ve " correspond à " naïf " correspond à " NA & # 304; VE " (Vous savez qu'une lettre majuscule i est & # 304; en turc? C'est pourquoi vous ignorez les accents)

Maintenant, le meilleur algorithme fait allusion à la réponse approuvée: utilisez NKD (décomposition) pour décomposer les lettres accentuées en une lettre de base et un accent séparé, puis supprimez tous les accents.

Cependant, la recomposition a peu d’intérêt par la suite. Vous avez supprimé la plupart des séquences qui changeraient, et les autres sont de toute façon identiques. Quelle est la différence entre & # 230; en NKC et & # 230; en NKD?

Je pense vraiment que vous devriez regarder à la racine du problème. Autrement dit, recherchez une solution qui vous permettra de prendre en charge les caractères codés en Unicode ou pour les paramètres régionaux de l'utilisateur.

Cela étant dit, votre problème est que vous avez affaire à des chaînes de plusieurs caractères. Il y a std :: wstring mais je ne suis pas sûr de l'utiliser. D'une part, les caractères larges ne sont pas conçus pour gérer des codages à largeur variable. Ce trou va très loin, alors je vais en rester là.

Maintenant, comme pour le reste de votre code, il est sujet aux erreurs car vous mélangez la logique de bouclage avec la logique de traduction. Ainsi, au moins deux types de bogues peuvent survenir: les bogues de traduction et les bogues en boucle. Utilisez la STL, cela peut vous aider beaucoup avec la partie en boucle.

Ce qui suit est une solution approximative pour remplacer des caractères dans une chaîne.

main.cpp :

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include "translate_characters.h"

using namespace std;

int main()
{
    string text;
    cin.unsetf(ios::skipws);
    transform(istream_iterator<char>(cin), istream_iterator<char>(),
              inserter(text, text.end()), translate_characters());
    cout << text << endl;
    return 0;
}

translate_characters.h :

#ifndef TRANSLATE_CHARACTERS_H
#define TRANSLATE_CHARACTERS_H

#include <functional>
#include <map>

class translate_characters : public std::unary_function<const char,char> {
public:
    translate_characters();
    char operator()(const char c);

private:
    std::map<char, char> characters_map;
};

#endif // TRANSLATE_CHARACTERS_H

translate_characters.cpp :

#include "translate_characters.h"

using namespace std;

translate_characters::translate_characters()
{
    characters_map.insert(make_pair('e', 'a'));
}

char translate_characters::operator()(const char c)
{
    map<char, char>::const_iterator translation_pos(characters_map.find(c));
    if( translation_pos == characters_map.end() )
        return c;
    return translation_pos->second;
}

Vous pouvez consulter le boost ( http://www.boost.org/ ). bibliothèque.

Il a une bibliothèque d’expression rationnelle que vous pouvez utiliser. De plus, il possède une bibliothèque spécifique qui contient certaines fonctions pour la manipulation de chaînes ( link ), y compris le remplacement.

Essayez d’utiliser std :: wstring au lieu de std :: string. UTF-16 devrait fonctionner (par opposition à ASCII).

Si vous le pouvez (si vous utilisez Unix), je vous suggère d'utiliser le tr pour cela: il est construit sur mesure à cette fin. Rappelez-vous, pas de code == pas de code buggy. : -)

Modifier: Désolé, vous avez raison, tr ne semble pas fonctionner. Qu'en est-il de sed ? C'est un script assez stupide que j'ai écrit, mais cela fonctionne pour moi.

#!/bin/sed -f
s/á/a/g;
s/é/e/g;
s/í/i/g;
s/ó/o/g;
s/ú/u/g;
s/ñ/n/g;

Je ne pouvais pas relier les bibliothèques ICU mais je pense toujours que c'est la meilleure solution. Comme j'ai besoin que ce programme soit fonctionnel le plus rapidement possible, j'ai créé un petit programme (que je dois améliorer) et je vais l'utiliser. Merci à tous pour vos suggestions et réponses.

Voici le code que je vais utiliser:

for (it= dictionary.begin(); it != dictionary.end(); it++)
{
    strMine=(it->first);
    found=toReplace.find(strMine);
    while (found != std::string::npos)
    {
        strAux=(it->second);
        toReplace.erase(found,2);
        toReplace.insert(found,strAux);
        found=toReplace.find(strMine,found+1);
    }
} 

Je le changerai la prochaine fois que je devrai remettre mon programme pour correction (dans environ 6 semaines).

    /// <summary>
    /// 
    /// Replace any accent and foreign character by their ASCII equivalent.
    /// In other words, convert a string to an ASCII-complient string.
    /// 
    /// This also get rid of special hidden character, like EOF, NUL, TAB and other '\0', except \n\r
    /// 
    /// Tests with accents and foreign characters:
    /// Before: "äæǽaeöœoeüueÄAeÜUeÖOeÀÁÂÃÄÅǺĀĂĄǍΑΆẢẠẦẪẨẬẰẮẴẲẶАAàáâãåǻāăąǎªαάảạầấẫẩậằắẵẳặаaБBбbÇĆĈĊČCçćĉċčcДDдdÐĎĐΔDjðďđδdjÈÉÊËĒĔĖĘĚΕΈẼẺẸỀẾỄỂỆЕЭEèéêëēĕėęěέεẽẻẹềếễểệеэeФFфfĜĞĠĢΓГҐGĝğġģγгґgĤĦHĥħhÌÍÎÏĨĪĬǏĮİΗΉΊΙΪỈỊИЫIìíîïĩīĭǐįıηήίιϊỉịиыїiĴJĵjĶΚКKķκкkĹĻĽĿŁΛЛLĺļľŀłλлlМMмmÑŃŅŇΝНNñńņňʼnνнnÒÓÔÕŌŎǑŐƠØǾΟΌΩΏỎỌỒỐỖỔỘỜỚỠỞỢОOòóôõōŏǒőơøǿºοόωώỏọồốỗổộờớỡởợоoПPпpŔŖŘΡРRŕŗřρрrŚŜŞȘŠΣСSśŝşșšſσςсsȚŢŤŦτТTțţťŧтtÙÚÛŨŪŬŮŰŲƯǓǕǗǙǛŨỦỤỪỨỮỬỰУUùúûũūŭůűųưǔǖǘǚǜυύϋủụừứữửựуuÝŸŶΥΎΫỲỸỶỴЙYýÿŷỳỹỷỵйyВVвvŴWŵwŹŻŽΖЗZźżžζзzÆǼAEßssIJIJijijŒOEƒf'ξksπpβvμmψpsЁYoёyoЄYeєyeЇYiЖZhжzhХKhхkhЦTsцtsЧChчchШShшshЩShchщshchЪъЬьЮYuюyuЯYaяya"
    /// After:  "aaeooeuueAAeUUeOOeAAAAAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaBbCCCCCCccccccDdDDjddjEEEEEEEEEEEEEEEEEEeeeeeeeeeeeeeeeeeeFfGGGGGgggggHHhhIIIIIIIIIIIIIiiiiiiiiiiiiJJjjKKkkLLLLllllMmNNNNNnnnnnOOOOOOOOOOOOOOOOOOOOOOooooooooooooooooooooooPpRRRRrrrrSSSSSSssssssTTTTttttUUUUUUUUUUUUUUUUUUUUUUUUuuuuuuuuuuuuuuuuuuuuuuuYYYYYYYYyyyyyyyyVvWWwwZZZZzzzzAEssIJijOEf'kspvmpsYoyoYeyeYiZhzhKhkhTstsChchShshShchshchYuyuYaya"
    /// 
    /// Tests with invalid 'special hidden characters':
    /// Before: "\0\0\000\0000Bj��rk�\'\"\\\0\a\b\f\n\r\t\v\u0020���oacu\'\\\'te�"
    /// After:  "00000Bjrk'\"\\\n\r oacu'\\'te"
    /// 
    /// </summary>
    private string Normalize(string StringToClean)
    {
        string normalizedString = StringToClean.Normalize(NormalizationForm.FormD);
        StringBuilder Buffer = new StringBuilder(StringToClean.Length);

        for (int i = 0; i < normalizedString.Length; i++)
        {
            if (CharUnicodeInfo.GetUnicodeCategory(normalizedString[i]) != UnicodeCategory.NonSpacingMark)
            {
                Buffer.Append(normalizedString[i]);
            }
        }

        string PreAsciiCompliant = Buffer.ToString().Normalize(NormalizationForm.FormC);
        StringBuilder AsciiComplient = new StringBuilder(PreAsciiCompliant.Length);

        foreach (char character in PreAsciiCompliant)
        {
            //Reject all special characters except \n\r (Carriage-Return and Line-Feed). 
            //Get rid of special hidden character, like EOF, NUL, TAB and other '\0'
            if (((int)character >= 32 && (int)character < 127) || ((int)character == 10 || (int)character == 13)) 
            {
                AsciiComplient.Append(character);
            }
        }
        return AsciiComplient.ToString().Trim(); // Remove spaces at start and end of string if any
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top