4

私のプロジェクトの1つでは、非常に単純な変数の検索と置換のパーサーを提供できる必要があります(主にパスで使用するため)。変数は主に起動時に使用され、ファイルにアクセスするために使用されることもあります(プログラムの主要な機能ではなく、リソースをロードするだけです)。したがって、パーサーは高性能である必要はありません。ただし、スレッドセーフであることが非常に望ましいです。

map<string, string>パーサーは、変数のセットを(現時点で)格納でき、トークンを文字列内の対応する値に置き換えることができる必要があります。変数値には他の変数が含まれている場合があります。これらの変数は、変数が使用されたときに解決されます(変数は時間の経過とともに追加される可能性があるため、追加されたときではありません)。

現在の可変文法は次のようになります。

$basepath$/resources/file.txt
/$drive$/$folder$/path/file

私の現在のパーサーは、stringstreams("output"と"varname")のペアを使用し、最初の$が見つかるまで "output"ストリームに書き込み、2番目の$まで "varname"ストリームに書き込み、次に変数を検索します(の内容varname.str())。これは非常に単純で、変数値を繰り返し処理する場合でもうまく機能します。

String Parse(String input)
{
    stringstream output, varname;
    bool dest = false;
    size_t total = input.length();
    size_t pos = 0;
    while ( pos < total )
    {
        char inchar = input[pos];
        if ( inchar != '$' )
        {
            if ( dest ) output << inchar;
            else varname << inchar;
        } else {
            // Is a varname start/end
            if ( !dest )
            {
                varname.clear();
                dest = true;
            } else {
                // Is an end
                Variable = mVariables.find(varname.str());
                output << Parse(Variable.value());
                dest = false;
            }
        }

        ++pos;
    }

    return output.str();
}

(エラーチェックなどは削除されました)

しかし、その方法を希望の文法に適用しようとすると失敗します。VisualStudioがプロジェクト変数に使用するものに似たものが欲しいです。

$(basepath)/resources/file.txt
/$(drive)/$(folder)/path/file

私もできるようにしたいと思います:

$(base$(path))/subdir/file

変数名を繰り返すと壁にぶつかり、最善の方法がわかりません。

現在、2つの考えられる概念があります。

$が見つかるまで入力文字列を繰り返し、(次の文字として(次の文字として、次に一致する)を見つけます)(適切なクローズパラーンに達するまでレベルをカウントします)。そのビットを送信して解析し、戻り値を変数名として使用します。ただし、これは面倒で多くのコピーが発生するようです。

2番目の概念はchar *、、またはおそらくを使用しchar * &、終了ヌルに到達するまでそれを前方に移動することです。パーサー関数は、変数名を解析している間、それ自体への再帰呼び出しでポインターを使用できます。各呼び出しで解析された名前を追跡し、呼び出しの戻り値を追加する以外に、この手法を実装する最善の方法がわかりません。

プロジェクトはVS2010でコンパイルするだけでよいので、STLストリームと文字列、C ++ 0xのサポートされているビット、およびMicrosoft固有の機能はすべて公正なゲームです(これらの要件が変更された場合は一般的なソリューションが望ましいですが、これは必要ありません点)。ただし、他のライブラリを使用することは良くありません。特にBoostはそうではありません。

私のアイデアはどちらも、必要以上に複雑で厄介なもののように思われるので、これを処理するためのすてきなクリーンな方法を探しています。それを行うための最善の方法を議論するコード、アイデア、またはドキュメントはすべて大歓迎です。

4

1 に答える 1

3

簡単な解決策は、文字列の最初の')'を検索し、後方に移動して、前に「$(」が付いた識別子があるかどうかを確認することです。ある場合は、それを置き換えてスキャンを再開します。「$(」が見つからない場合"識別子、次に次の')'を見つけます-終了したものがない場合。

説明:を検索する)ことで、置換の完全な識別子を確実に見つけることができます。これにより、後続の置換で使用される他の識別子に貢献することができます。

Had a great time on $($(day)$(month)), did you?

Dictionary: "day" -> "1", "month" -> "April", "1April" -> "April Fools Day"

Had a great time on $($(day)$(month)), did you?
                           ^ find this
Had a great time on $($(day)$(month)), did you?
                      ^^^^^^ back up to match this complete substitution
Had a great time on $(1$(month)), did you?
                      ^ substitution made, restart entire process...
Had a great time on $(1$(month)), did you?
                              ^ find this
etc.
于 2011-04-04T02:45:03.643 に答える