C ++ std :: stringでアクセントとチルダを削除する方法
-
02-07-2019 - |
質問
スペイン語のいくつかの単語を含むC ++の文字列に問題があります。これは、アクセントとチルダが付いた単語がたくさんあることを意味します。それらをアクセントのない対応するものに置き換えたいと思います。例:この単語を置き換えたい:" habí a"ハビアのために。直接置き換えようとしましたが、文字列クラスのreplaceメソッドを使用しましたが、動作させることができませんでした。
このコードを使用しています:
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="á-é-í-ó-ú-ñ-á-é-í-ó-ú-ñ";
明らかに何かが欠けているに違いありません。わかりません。 使用できるライブラリはありますか?。
ありがとう、
解決
まず、これは本当に悪い考えです。あなたは文字を削除することで誰かの言語をマングしています。ただし、&#8220; na&#239; ve&#8221;のような単語の余分なドットは英語しか話せない人には不必要に思えますが、文字通り数千の書記体系があり、そのような区別は非常に重要です。誰かのスピーチを切り取るソフトウェアを書くと、人間の表現の領域と抑圧のツールの領域を広げる手段として、コンピュータを使用することの間の緊張の間違った側にあなたを正に置きます。
これを行おうとしている理由は何ですか?さらに何かがアクセントを詰まらせているのでしょうか?多くの人々はあなたがそれを解決するのを手伝いたいです。
とはいえ、libicuはあなたのためにこれを行うことができます。 変換デモを開きます。スペイン語のテキストをコピーして&#8220;入力&#8221;に貼り付けますボックス;入力
NFD; [:M:] remove; NFC
as&#8220; Compound 1&#8221;変換をクリックします。
( ICUでのUnicode変換のスライド9の助けを借りて。 APIを使用します。)
他のヒント
現在「承認済み」に同意しません。回答。この質問は、テキストのインデックスを作成する場合に最適です。大文字と小文字を区別しない検索と同様に、アクセントを区別しない検索は良いアイデアです。 &quot; na&#239; ve&quot; 「Na&#239; ve」に一致&quot; naive&quot;と一致「NA&#304; VE」に一致(大文字のiがトルコ語では&#304;であることをします?それがアクセントを無視する理由です)
今、承認された答えで最良のアルゴリズムが示唆されています:NKD(分解)を使用して、アクセント付き文字をベース文字と別のアクセントに分解し、すべてのアクセントを削除します。
しかし、その後の再構成にはほとんど意味がありません。変更するほとんどのシーケンスを削除しましたが、他のシーケンスはいずれにせよすべての意図と目的のためのものです。違いは&#230;の違いですNKCおよび&#230; NKDで?
間違いなく問題の根本を調べるべきだと思います。つまり、Unicodeまたはユーザーのロケールでエンコードされた文字をサポートできるソリューションを探します。
とはいえ、あなたの問題は、複数文字の文字列を扱っていることです。 std :: wstring
がありますが、それを使用するかどうかはわかりません。一つには、ワイド文字は可変幅エンコーディングを処理するためのものではありません。この穴は深くなるので、そのままにしておきます。
これで、コードの残りの部分については、ループロジックと変換ロジックを混在させるため、エラーが発生しやすくなります。したがって、少なくとも2種類のバグが発生する可能性があります。翻訳バグとループバグです。 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;
}
ブーストを確認することもできます( http://www.boost.org/ )ライブラリ。
正規表現ライブラリがあり、使用できます。 さらに、文字列操作のためのいくつかの機能を持つ特定のライブラリがあります(リンク)置換を含む。
std :: stringの代わりにstd :: wstringを使用してみてください。 UTF-16は(ASCIIではなく)動作するはずです。
可能な場合(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;
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週間以内)に変更します。
/// <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
}