2

同様の質問をしましたが、重要な詳細を省略しました。文字の配列(cstring)でテキスト処理を行っています。入力配列は出力配列にコピーされますが、特定の文字が変更されます (a->b など)。これは、switch ステートメントを使用して行います。私が望むのは、特定の文字が2つ以上連続して見つかった場合、そのうちの1つだけが新しい配列にコピーされることです(したがって、2つのスペースを連続して使用したくありません)。

これは私がこれまでに得たものであり、特定の文字の行で2つ以上をスキップすることなく機能します:

char cleanName[ent->d_namlen];
    for(int i = 0; i < ent->d_namlen; i++)
    {
        switch(ent->d_name[i])
        {

            case 'a' :
                cleanName[i] = 'b';//replace a's with b's (just an example)
                break;
            case ' ' ://fall through
            case '-' :
            case '–' :
            case '—' :
                cleanName[i] = '_';//replace spaces and dashes with spaces
                break;
            ....//more case statments
           default: 
                cleanName[i] = ent->d_name[i];
  }
}

たとえば、連続する 2 つの文字がアンダースコアに置き換えられた場合、どうすればよいでしょうか? switchステートメントを実行するだけですかif(ent->d_name[i] != previous || (ent->d_name[i] != '-' && ent->d_name[i] != '_' && ent->d_name[i] != ' ')

これは、実装固有の問題というよりもアルゴリズムの問​​題かもしれません。

入力例: abbc--de
出力: bbbc_d_e (簡単にするために、'a' が 'b' にマップされていると仮定しますが、実際にはこれ以上のものがあります)

4

5 に答える 5

2

そのようなクラスのテキスト処理アルゴリズムには、ステート マシンを使用します。

于 2012-08-31T19:54:05.043 に答える
2

std::unique最も簡単なのは、既存の変換後にカスタム述語を使用することです。

cleanName.erase(std::unique(std::begin(cleanName), std::end(cleanName),
    [](char c, char d) { return c == '_' && d == '_'; }), std::end(cleanName));

char配列の場合:

length = std::unique(cleanName, &cleanName[length],
    [](char c, char d) { return c == '_' && d == '_'; }) - cleanName;
cleanName[length] = '\0';
于 2012-08-31T19:54:21.857 に答える
0

unique_copyアルゴリズムとtransform_iteratorBoost からのアイデアは次のとおりです。

#include <boost/iterator/transform_iterator.hpp>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>

char transform(char c)
{
    switch(c) {
        case 'a' :
            return 'b';
        case ' ' :
        case '-' :
        case '–' :
        case '—' :
            return '_';
        default:
            return c;
    }
}

int main()
{
    std::string in = "abbc--d-e";
    std::string out;

    std::unique_copy(
        boost::make_transform_iterator(in.begin(), transform),
        boost::make_transform_iterator(in.end(), transform),
        std::back_inserter(out),
        [](char c1, char c2){ return c1 == '_' && c2 == '_'; });

    std::cout << out; // bbbc_d_e
}
于 2012-08-31T21:29:29.420 に答える
0

注意すべきことの 1 つは、インデックス作成の方法では、cleanName の長さが必ずしも入力配列と同じ長さになるとは限らないことを認識する必要があることです。そのため、インデックス i には注意する必要があります。

于 2012-08-31T19:55:26.420 に答える
0

私の提案は、最後に見つかった文字を一時変数に保持することです。これにより、同じ文字が表示されても無視できます。これには 2 つの方法があります。
switch の後に while ステートメントを追加します。これにより、最後に見つかった文字と等しいすべての文字が消費されます。これは、cstring に多くの繰り返し文字がある場合に役立ちます。

 char cleanName[ent->d_namlen];
 char parent;
    for(int i = 0; i < ent->d_namlen; i++)
    {
        switch(ent->d_name[i])
        {
            case 'a' :
                cleanName[i] = 'b';//replace a's with b's (just an example)
                parent = ent->d_name[i];
                break;
            case ' ' ://fall through
            case '-' :
            case '–' :
            case '—' :
                cleanName[i] = '_';//replace spaces and dashes with spaces
                parent = ent->d_name[i];
                break;
            ....//more case statments
           default: 
                cleanName[i] = ent->d_name[i];
        }
        while((parent == ent->d_name[i++]) && ent->d_name[i++] != NULL)
            i++;
    }

ここでの唯一の問題は、さまざまなインターリーブされた一連のスペースとダッシュがある場合、それが認識されず、さまざまな "_" が保持される可能性があることです。1 つの解決策は、単一の文字ではなく、親のコレクションを保持することです。

もう 1 つの方法は、反復ごとに現在の文字を次の文字と比較することです。「親」変数を保持し、各スイッチケースで現在の文字を親と比較し、それらが同じ場合は cleanName cstring に追加しません。

于 2012-08-31T20:09:07.553 に答える