2008-09-27 115 views
12

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 reemplazar el método de la clase de cadena, pero no pude hacer que funcionara.Cómo eliminar acentos y tilde en C++ std :: string

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

Dónde dictionary es un mapa como éste (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 cuerdas es:

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

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

Gracias,

+0

Debe agregar la plataforma a la que se dirige (Windows, Linux, etc.) y la codificación a la que se dirige (UTF-8, UTF-16, lo que sea). Por ejemplo, su "á" es el glifo E1, que traduce "á" en USO-8859-1 char, L'á 'en UTF-16 wchar_t, pero "á" (sí, dos caracteres) en UTF-8 – paercebal

+0

Lo siento ... Para cuando volví a tu publicación (de buscar en Unicode.org) y validé el comentario, respondiste ... – paercebal

Respuesta

16

En primer lugar, esta es una muy mala idea: estás destruyendo el lenguaje de alguien al eliminar las letras. Aunque los puntos extra en palabras como "ingenuo" 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. Escribir software para mutilar el habla de alguien te coloca directamente en el lado equivocado de la tensión entre usar computadoras como medio para ampliar el ámbito de la expresión humana frente a las herramientas de opresión.

¿Cuál es la razón por la que intentas hacer esto? ¿Hay algo más allá en la línea de asfixia en los acentos? A muchas personas les encantaría ayudarte a resolver eso.

Dicho esto, libicu puede hacer esto por usted.Abra el transform demo; copie y pegue su texto en español en el cuadro "Entrada"; ingrese

NFD; [:M:] remove; NFC 

como "Compuesto 1" y haga clic en transformar.

(Con la ayuda de corredera 9 de Unicode Transforms in ICU. Diapositivas 29-30 muestran cómo utilizar la API.)

+0

Bueno, soy de Argentina, que es un país de habla española, así que estoy bastante cubierto allí con la primera parte Permítanme dar más detalles en la respuesta a continuación. – Alejo

+1

De todos modos, creo que es una buena solución, la ICU – Alejo

+2

¡Adelante! Acentos y tildes no están ahí para ser lindos; cortarlos cambiará el significado del texto. "Habia" no es una palabra sino "había" es. "Carácter" es "personalidad", un "carácter" es un símbolo impreso. "Cana" es un cabello blanco, "Caña" es un bastón. "Peso" es un sustantivo ". Pesó "es un verbo. –

0

Si usted puede (si se está ejecutando Unix), se sugiere emplear la instalación tr para esto: es hecha a la medida para este fin. Recuerde, no hay código == no hay código con errores. :-)

Editar: Lo sentimos, tienes razón, tr parece que no funciona. ¿Qué hay de sed? Es un guión 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; 
0

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

Tiene una biblioteca de expresiones regulares, que puede usar. Además, tiene una biblioteca específica que tiene algunas funciones para la manipulación de cadenas (link) incluyendo replace.

0

que estaba usando UNIX, se me olvidó mencionar que, pero me gusta este tr ejecutar

$ tr aeiou aeiou
a-e-í-O-u
ue-uo-uu-uu- uu

no funciona como se espera. Creo que tiene que ver con unicode y string class.

+0

Sí, eso es extraño. Descargué el código fuente de GNU sed y no usa ningún carácter ancho. :-(Pero no importa! Tengo una solución sed, que no requiere un amplio soporte de caracteres. :-P –

0

La cosa es que estoy desarrollando una aplicación debido en 5 días para la universidad. Es un programa que indexará el texto dentro de la etiqueta en páginas HTML (no puedo usar apache lucene para crear el índice también). Sin embargo, no voy a indexar todas las palabras, debo eliminar todas las palabras vacías, usar la derivación y hacer todo el texto en minúscula. Según lo solicitado por nuestro maestro, debemos eliminar acentos y tilde en las palabras. Espero que esto aclare un poco las cosas.

Saludos,

+0

Ah, eso tiene sentido. Lamento ser duro ... – andrewdotn

+0

Estoy de acuerdo con www.blindrut.ca/~neitsch, y lo siento también; Espero que no te importe, pero nuestros comentarios deben mantenerse en su lugar, para la siguiente persona que tenga la misma pregunta. –

0

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

2

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

Habiendo dicho eso, su problema es que se trata de cadenas de caracteres múltiples. Hay std::wstring pero no estoy seguro de que use eso. Por un lado, los caracteres anchos no están destinados a manejar codificaciones de ancho variable. Este agujero es profundo, así que lo dejo 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 bucles. Utiliza STL, puede ayudarte 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; 
} 
+0

Estás mapeando . pero utf-8 "ñ" (por ejemplo) no es (equivalente a) un char (sino algo de 2 bytes en realidad). Esta es una buena técnica sobre la marcha, pero es mucho más complicado que eso, supongo. – lajarre

0

No pude vincular las bibliotecas de ICU, pero sigo pensando que es la mejor solución. Como necesito que este programa sea funcional lo más pronto 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); 
    } 
} 

que va a cambiar la próxima vez tengo que cambiar mi programa para la corrección (en aproximadamente 6 semanas).

23

No estoy de acuerdo con la respuesta actualmente "aprobada". La pregunta tiene mucho sentido cuando indexas texto. Al igual que la búsqueda insensible a mayúsculas/minúsculas, la búsqueda insensible al acento es una buena idea. partidos "ingenuos" partidos "ingenuos" partidos "ingenuos" "NAİVE" (usted hacer saber que una mayúscula es İ en turco?Es por eso que ignora 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 de la base y un acento separado, y luego elimine todos los acentos.

Sin embargo, tiene poco sentido volver a la composición. Eliminaste la mayoría de las secuencias que cambiarían, y las demás son, para todos los efectos, idénticas de todos modos. ¿Cuál es la diferencia entre æ en NKC y æ en NKD?

+0

su teoría se desmorona en alemán. "bär" (oso) se comparará con "baer" (oso) pero no con "bar" (bar). – hop

+3

En realidad, no es así. La descomposición Unicode de bär da ba r (usando un punto de código adicional para la diéresis), no baer. Remmeber que la descomposición Unicode es independiente de la localización ä = ae es una descomposición alemana, pero no por ejemplo holandesa. – MSalters

+0

Creo que quieres decir ' İ ', no' Ï 'para una' i 'mayúscula. –

1

Me sorprende que algunas personas digan que no debes desacralizar a los personajes. Tener acentos en los caracteres de los nombres de archivos puede provocar muchos problemas cuando se utilizan programas escritos de manera manifiesta por programadores que no permitieron esto.

1

Estoy totalmente 100% a favor de usar Unicode y no perder información importante como acentos, pero a veces tienes que hacer algo como esto. Lo mejor es no adivinar las razones de las personas para querer una función en particular. En mi caso, estoy buscando hacer esto con el fin de buscar textos "similares" (lo que a menudo significa textos escritos, incorrectamente, sin acentos).

Alguien siempre tendrá un motivo válido.

Cuestiones relacionadas