Как удалить акценты и тильду в С++ std::string
У меня проблема со строкой в С++, которая имеет несколько слов на испанском языке. Это означает, что у меня много слов с акцентами и тильдами. Я хочу заменить их для своих акцентированных коллег. Пример: Я хочу заменить это слово: "había" для habia. Я попытался заменить его напрямую, но заменил метод класса string, но я не мог заставить это работать.
Я использую этот код:
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);
}
}
Где dictionary
- это карта, подобная этой (с большим количеством записей):
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") );
Строки
и toReplace
:
std::string toReplace="á-é-í-ó-ú-ñ-á-é-í-ó-ú-ñ";
Я, очевидно, должен что-то упустить. Я не могу понять.
Есть ли библиотека, которую я могу использовать?
Спасибо,
Ответы
Ответ 1
Во-первых, это очень плохая идея: youre mangling somebodys language путем удаления букв. Хотя дополнительные точки в словах типа "наивные" кажутся излишними для людей, которые говорят по-английски, в мире существует буквально тысячи письменных систем, в которых такие различия очень важны. Написание программного обеспечения для искажения речи некоторых людей ставит вас прямо на неправильную сторону напряжения между использованием компьютеров в качестве средства расширения сферы человеческого выражения против инструментов угнетения.
Чем вы пытаетесь это сделать? Что-то дальше по линии, задыхаясь от акцентов? Многие люди хотели бы помочь вам в этом.
Тем не менее, libicu может сделать это за вас. Откройте трансформировать демо; скопируйте и вставьте свой испанский текст в поле "Вход"; введите
NFD; [:M:] remove; NFC
как "Соединение 1" и щелкните преобразование.
(С помощью слайда 9 Unicode Transforms в ICU. Слайды 29-30 показывают, как использовать API.)
Ответ 2
Я не согласен с утвержденным в настоящее время ответом. Вопрос имеет смысл, когда вы индексируете текст. Подобно нечувствительным к регистру поискам, поиск без учета акцентов - хорошая идея. "наивные" матчи "Наивные" соответствуют "наивным" матчам "NAİVE" (вы знаете, что в верхнем регистре я İ на турецком? Почему вы игнорируете акценты)
Теперь наилучший алгоритм намекает на одобренный ответ: используйте NKD (разложение), чтобы разложить акцентированные буквы в базовую букву и отдельный акцент, а затем удалить все акценты.
Тем не менее, в перекомпозиции мало смысла. Вы удалили большинство последовательностей, которые изменились бы, а остальные все равно были бы идентичны. Какая разница между æ в НКК и æ в НКД?
Ответ 3
Я определенно думаю, что вы должны изучить корень проблемы. То есть, найдите решение, которое позволит вам поддерживать символы, закодированные в Юникоде или для локали пользователя.
Говоря, ваша проблема заключается в том, что вы имеете дело с многосимвольными строками. Существует std::wstring
, но я не уверен, что буду использовать это. Во-первых, широкие символы не предназначены для обработки кодировок переменной ширины. Это отверстие проходит глубоко, поэтому я оставлю это на этом.
Теперь, что касается остальной части вашего кода, он подвержен ошибкам, потому что вы смешиваете логику цикла с логикой перевода. Таким образом, могут возникать как минимум два типа ошибок: ошибки перевода и ошибки цикла. Используйте STL, это может помочь вам с частью цикла.
Ниже приводится грубое решение для замены символов в строке.
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;
}
Ответ 4
Я удивлен, что некоторые люди говорят, что вы не должны деактивировать персонажей. Имея акценты на символы в именах файлов, вы можете столкнуться с множеством проблем при использовании программ, явно написанных программистами, которые этого не допускали.
Ответ 5
Я полностью 100% в пользу использования Unicode и не теряю важной информации, такой как акценты, но иногда вам нужно сделать что-то вроде этого. Лучше не предполагать, что люди предпочитают какую-то конкретную функцию. В моем случае я хочу сделать это для поиска "похожих" текстов (что часто означает, что тексты написаны неправильно - без акцентов).
У кого-то всегда будет веская причина.
Ответ 6
Если вы можете (если вы используете Unix), я предлагаю использовать tr
для этого: он выполнен на заказ для этой цели. Помните, что нет кода == no buggy code.: -)
Изменить: Извините, вы правы, tr
, похоже, не работает. Как насчет sed
? Это довольно глупый script, который я написал, но он работает для меня.
#!/bin/sed -f
s/á/a/g;
s/é/e/g;
s/í/i/g;
s/ó/o/g;
s/ú/u/g;
s/ñ/n/g;
Ответ 7
Возможно, вы захотите проверить библиотеку boost (http://www.boost.org/).
У него есть библиотека regexp, которую вы можете использовать.
Кроме того, он имеет определенную библиотеку, которая имеет некоторые функции для управления строкой (ссылка), включая замену.
Ответ 8
Я использовал unix, я забыл упомянуть об этом, но я запускаю tr как это
$tr áéíóú aeiou
-е-е-ó-ú
уй-ио-уу-уу-уу
он не работает, как ожидалось. Я думаю, что это связано с unicode и строковым классом.
Ответ 9
Дело в том, что я разрабатываю заявку в течение 5 дней для университета. Это программа, которая будет индексировать текст внутри тега в HTML-страницах (я не могу использовать apache lucene для создания индекса). Однако я не буду индексировать все слова, должен удалить все стоп-слова, используя их, и сделать весь текст в нижнем регистре. По просьбе нашего учителя мы должны исключить акценты и тильду в словах.
Надеюсь, что это немного упростит.
Saludos,
Ответ 10
Попробуйте использовать std:: wstring вместо std::string. UTF-16 должен работать (в отличие от ASCII).
Ответ 11
Я не мог связать библиотеки ICU, но я все же считаю это лучшим решением. Поскольку мне нужно, чтобы эта программа была работоспособной как можно скорее, я сделал небольшую программу (которую я должен улучшить), и я буду использовать ее. Спасибо всем за предложения и ответы.
Вот код, который я буду использовать:
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);
}
}
Я буду менять его в следующий раз, когда мне придется повернуть мою программу для исправления (примерно через 6 недель).