我在使用C ++中的字符串时遇到问题,该字符串有几个西班牙语单词。这意味着我有很多带有重音符号和波浪号的单词。我想替换他们没有重音的同行。示例:我想替换这个词:哈比亚的“había”。我尝试直接替换它但使用字符串类的替换方法,但我无法使其工作。
我正在使用此代码:
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="á-é-í-ó-ú-ñ-á-é-í-ó-ú-ñ";
我显然必须遗漏一些东西。我无法弄清楚。 我可以使用任何图书馆吗?。
谢谢,
答案 0 :(得分:23)
我不同意目前“批准”的答案。在索引文本时,这个问题非常有意义。与不区分大小写的搜索一样,重音不敏感搜索是个好主意。 “naïve”匹配“Naïve”匹配“天真”匹配“NAİVE”(你做知道大写我是土耳其语?这就是你忽略重音的原因)
现在,最好的算法暗示了批准的答案:使用NKD(分解)将重音字母分解为基本字母和单独的重音,然后删除所有重音。
但是,之后的重组很少有点意义。您删除了大多数会改变的序列,而其他序列无论如何都是相同的。什么是NKC中的æ和NKD中的æ之间的区别?答案 1 :(得分:17)
首先,这是一个非常糟糕的主意:你通过删除字母来破坏某人的语言。尽管像“天真”这样的单词中的额外点对于只说英语的人来说似乎是多余的,但世界上有数以千计的书写系统,其中这些区别非常重要。编写软件以破坏某人的言论,这使你在使用计算机作为拓宽人类表达领域与压迫工具的手段之间的紧张关系的错误方面。
你试图这样做的原因是什么?是什么东西在口音上窒息?很多人都愿意帮助你解决这个问题。
那就是说,libicu可以为你做到这一点。打开transform demo;将西班牙文本复制并粘贴到“输入”框中;输入
NFD; [:M:] remove; NFC
作为“化合物1”并单击转换。
(在Unicode Transforms in ICU幻灯片9的帮助下。幻灯片29-30显示了如何使用API。)
答案 2 :(得分:2)
我绝对认为你应该研究问题的根源。也就是说,寻找一种解决方案,允许您支持以Unicode或用户的语言环境编码的字符。
话虽这么说,你的问题是你正在处理多字符串。有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;
}
答案 3 :(得分:0)
如果可以(如果您正在运行Unix),我建议使用tr
工具:它是为此目的而定制的。记住,没有代码==没有错误的代码。 : - )
编辑:对不起,您是对的,tr
似乎不起作用。 sed
怎么样?这是我编写的一个非常愚蠢的剧本,但它对我有用。
#!/bin/sed -f
s/á/a/g;
s/é/e/g;
s/í/i/g;
s/ó/o/g;
s/ú/u/g;
s/ñ/n/g;
答案 4 :(得分:0)
您可能需要查看boost(http://www.boost.org/)库。
它有一个正则表达式库,您可以使用它。 另外它有一个特定的库,它有一些字符串操作函数(link),包括replace。
答案 5 :(得分:0)
尝试使用std :: wstring而不是std :: string。 UTF-16应该工作(而不是ASCII)。
答案 6 :(得分:0)
我无法链接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周),我会更改它。
答案 7 :(得分:0)
/// <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
}