17

スペイン語の単語がいくつかあるC++の文字列に問題があります。これは、アクセントやチルダのある単語がたくさんあることを意味します。アクセントのないものと交換したいと思います。例:この単語を置き換えたい:habiaの「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="á-é-í-ó-ú-ñ-á-é-í-ó-ú-ñ";

私は明らかに何かが欠けているに違いありません。私はそれを理解することはできません。使用できるライブラリはありますか?

ありがとう、

4

8 に答える 8

30

私は現在「承認された」答えに同意しません。テキストのインデックスを作成する場合、この質問は完全に理にかなっています。大文字と小文字を区別しない検索と同様に、アクセントを区別しない検索は良い考えです。「naïve」は「Naïve」と一致します「naive」は「NAİVE」と一致します(大文字のiがトルコ語でİであることを知っていますか?そのため、アクセントを無視します)

ここで、承認された答えに最適なアルゴリズムが示唆されます。NKD(分解)を使用して、アクセント付き文字をベース文字と個別のアクセントに分解し、すべてのアクセントを削除します。

ただし、その後の再構成にはほとんど意味がありません。変更される可能性のあるほとんどのシーケンスを削除しましたが、他のシーケンスはすべての目的と目的で同じです。NKCのæとNKDのæの違いは何ですか?

于 2008-09-29T12:43:41.133 に答える
20

まず、これは本当に悪い考えです。文字を削除することで、誰かの言語を台無しにしています。「ナイーブ」などの単語の余分なドットは、英語しか話せない人にとっては不必要に思えるかもしれませんが、そのような区別が非常に重要な文字体系が世界には文字通り何千もあります。誰かの言論を台無しにするソフトウェアを書くことは、人間の表現の領域を広げる手段としてコンピュータを使用することと、抑圧の道具として使用することとの間の緊張関係の、真っ向から反対側に立つことになります。

これをやろうとしている理由は何ですか?アクセントを窒息させている何かがさらに下にありますか?多くの人があなたがそれを解決するのを助けたいと思っています.

そうは言っても、libicu はあなたのためにこれを行うことができます。変換デモを開きます。スペイン語のテキストをコピーして「入力」ボックスに貼り付けます。入力

NFD; [:M:] remove; NFC

「化合物1」として、変換をクリックします。

( ICU での Unicode Transformsのスライド 9 を参考にしてください。スライド 29 ~ 30 は、API の使用方法を示しています。)

于 2008-09-28T00:02:25.137 に答える
2

問題の根本に目を向けるべきだと思います。つまり、Unicode またはユーザーのロケールでエンコードされた文字をサポートできるソリューションを探してください。

そうは言っても、問題は複数文字の文字列を扱っていることです。ありますがstd::wstring、それを使用するかどうかはわかりません。1 つには、ワイド文字は可変幅エンコーディングを処理するためのものではありません。この穴は深いのでそのままにしておきます。

コードの残りの部分については、ループ ロジックと変換ロジックが混在しているため、エラーが発生しやすくなっています。したがって、少なくとも 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;
}
于 2008-09-28T06:47:56.537 に答える
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週間以内)。

于 2008-09-29T03:05:29.680 に答える
0

ブースト ( http://www.boost.org/ ) ライブラリをチェックアウトすることをお勧めします。

使用できる正規表現ライブラリがあります。さらに、replace を含む文字列操作 ( link )のためのいくつかの関数を備えた特定のライブラリがあります。

于 2008-09-27T23:55:07.870 に答える
0

std::string の代わりに std::wstring を使用してみてください。(ASCII ではなく) UTF-16 が機能するはずです。

于 2008-09-28T00:26:33.660 に答える
-1

可能であれば(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;
于 2008-09-27T23:43:58.380 に答える