Pregunta

Tengo un problema con una cadena en C ++ que tiene varias palabras en español. Esto significa que tengo muchas palabras con acentos y tildes. Quiero reemplazarlos por sus homólogos no acentuados. Ejemplo: quiero reemplazar esta palabra: " había " por habia. Intenté reemplazarlo directamente pero con el método de reemplazo de la clase de cadena pero no pude hacer que funcionara.

Estoy usando este código:

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);
    }
}

Donde dictionary es un mapa como este (con más entradas):

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") );

y toReplace son:

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

Obviamente debo estar perdiendo algo. No puedo resolverlo. ¿Hay alguna biblioteca que pueda usar?

Gracias,

¿Fue útil?

Solución

Primero, esta es una muy mala idea: estás manipulando el lenguaje de alguien eliminando las letras. Aunque los puntos adicionales en palabras como & # 8220; na & # 239; ve & # 8221; Parecen superfluos para las personas que solo hablan inglés, hay literalmente miles de sistemas de escritura en el mundo en los que tales distinciones son muy importantes. El software de escritura para mutilar el discurso de alguien te pone directamente en el lado equivocado de la tensión entre usar las computadoras como medio para ampliar el ámbito de la expresión humana frente a las herramientas de la opresión.

¿Cuál es la razón por la que estás tratando de hacer esto? ¿Hay algo más abajo en la línea que se atraganta con los acentos? A muchas personas les encantaría ayudarte a resolver eso.

Dicho esto, libicu puede hacer esto por ti. Abra la demostración demo ; copie y pegue su texto en español en la sección & # 8220; Entrada & # 8221; caja; entrar

NFD; [:M:] remove; NFC

como & # 8220; Compound 1 & # 8221; y haga clic en transformar.

(Con la ayuda de la diapositiva 9 de Transformaciones de Unicode en la UCI . Las diapositivas 29-30 muestran cómo para utilizar la API.)

Otros consejos

No estoy de acuerdo con el " actualmente " aprobado " responder. La pregunta tiene mucho sentido cuando estás indexando texto. Al igual que la búsqueda insensible a mayúsculas y minúsculas, la búsqueda insensible a los acentos es una buena idea. " na & # 239; ve " coincide con " Na & # 239; ve " coincide con " ingenuo " coincide con " NA & # 304; VE " (¿ sabes que una mayúscula es & # 304; en turco? Por eso ignoras los acentos)

Ahora, el mejor algoritmo se insinúa en la respuesta aprobada: use NKD (descomposición) para descomponer las letras acentuadas en la letra base y un acento separado, y luego elimine todos los acentos.

Sin embargo, hay poco sentido en la re-composición después. Eliminó la mayoría de las secuencias que cambiarían, y las demás son idénticas para todos los propósitos y propósitos. ¿Cuál es la diferencia entre & # 230; en NKC y & # 230; en NKD?

Definitivamente creo que deberías buscar en la raíz del problema. Es decir, busque una solución que le permita admitir caracteres codificados en Unicode o para la configuración regional del usuario.

Dicho esto, su problema es que se trata de cadenas de caracteres múltiples. Hay std :: wstring pero no estoy seguro de que lo use. Por un lado, los caracteres anchos no están diseñados para manejar codificaciones de ancho variable. Este agujero se profundiza, así que lo dejaré así.

Ahora, en cuanto al resto de su código, es propenso a errores porque mezcla la lógica de bucle con la lógica de traducción. Por lo tanto, al menos dos tipos de errores pueden ocurrir: errores de traducción y errores de bucle. Utilice el STL, puede ayudarlo mucho con la parte de bucle.

La siguiente es una solución aproximada para reemplazar caracteres en una cadena.

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;
}

Es posible que desee revisar el impulso ( http://www.boost.org/ ) biblioteca.

Tiene una biblioteca regexp, que puedes usar. Además, tiene una biblioteca específica que tiene algunas funciones para la manipulación de cadenas ( link ) incluyendo reemplazar.

Intente usar std :: wstring en lugar de std :: string. UTF-16 debería funcionar (a diferencia de ASCII).

Si puede (si está ejecutando Unix), sugiero usar tr para esto: está hecho a medida para este propósito. Recuerde, no hay código == no hay código de buggy. :-)

Editar: Lo siento, tienes razón, tr no parece funcionar. ¿Qué tal sed ? Es un script bastante estúpido que he escrito, pero funciona para mí.

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

No pude vincular las bibliotecas de la UCI, pero sigo pensando que es la mejor solución. Como necesito que este programa sea funcional lo antes posible, hice un pequeño programa (que tengo que mejorar) y lo voy a usar. Gracias a todos por sus sugerencias y respuestas.

Aquí está el código que voy a usar:

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);
    }
} 

Lo cambiaré la próxima vez que tenga que entregar mi programa para corregirlo (en aproximadamente 6 semanas).

    /// <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
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top