1

要約すると、正規表現パターンが文字列のセグメントを単語全体の変数名と間違えないようにするにはどうすればよいですか? 単語の境界を使用していても、より大きな単語の一部である文字を置き換えています\b

私がやろうとしていること:私は電卓に取り組んでいます。これには変数のリストがあり、式をパーサーに渡す前に、関数を呼び出して、ParseVars()変数regex_searchマッチングのパターンを使用します。変数パターンに一致するすべてのトークンを取得したら、その文字列が実際に変数名のリストにあるかどうかを確認し、そうであれば、文字列を変数値に置き換えます。また、パーサーで計算が行われるたびに、 、 などの名前ans1で定数を定義ans2します。

問題は:aという名前の変数が定義されていて、その値が であるとしましょう6。(ちなみに、これらを a で追跡するmap<string,double> Vars;ParseVars("ans1")、結果の文字列は になります"ans1"。また、 を使用してもParseVar()、文字列ans1+ans2+9は同じままです。文字列は に9+aなり9+6ます。したがって、これまでのところ、私の正規表現は期待どおりに機能します。

しかし、そうするとParseVars("ans1+a")、結果の文字列は"6ns1+6". 変数を使用した場合にのみ正規表現の単語境界が失敗する理由について混乱しています。「a」は常に「ans1」で見つかりますが、「a」が文字列のどこかに単独である場合にのみ置き換えられます.

私が持っているもの:これが私の正規表現パターンです:\b([a-z][a-z0-9_]*)\bこれは単語全体にのみ一致するべきではありませんか? 単語境界は、'a' が文字列内のどこかで単独になるまで正常に機能します。多分それは私のParseVars()機能です、ここにコードがあります:

map<string,double> Vars;

// Variables must be a whole word, start with a letter, and
// optionally have other letters, numbers, and underscores.
sregex VarPattern = sregex::compile("\\b([a-z][a-z0-9_]*)\\b");

string Calculator::ParseVars(string expr) {
    if (Vars.empty()) return expr;

    string newExpr = StrToLower(expr);
    const sregex_iterator End;

    // Loop through all possible variable matches
    for (sregex_iterator i(expr.begin(), expr.end(), VarPattern); i != End; ++i) {
        string name = (*i)[0];

        // If it is a variable
        if (Vars.find(name) != Vars.end()) {
            int rPos = 0;

            // Replace all occurrences of it
            while ((rPos = newExpr.find(name, rPos)) != string::npos) {
                newExpr.replace(
                    rPos, name.length(),
                    lexical_cast<string,double>(Vars[name])
                );
            }
        }
    }

    return newExpr;
}

a等しいので6、どうすれば望ましいのではなくans1+aなるのを防ぐことができますか?6ns1+6ans1+6

4

1 に答える 1

2

さて、私は解決策を見つけました。同様の問題に遭遇した人のために、ここに私の答えを載せています。

問題は、正規表現が一致した後に基本的な文字列置換を使用していたため、単語の境界が機能したことでした。文字列の置換関数が、単語の境界に関係なく、文字列のすべての出現を置換していただけです。を使用する必要がありますregex_replace()。最終的には次のようになりました。

map<string,double> Vars;

// Variables must be a whole word, start with a letter, and
// optionally have other letters, numbers, and underscores.
sregex VarPattern = sregex::compile("\\b([a-z][a-z0-9_]*)\\b");

string Calculator::ParseVars(string expr) {
    if (Vars.empty()) return expr;
    string newExpr = StrToLower(expr);
    const sregex_iterator End;

    // Loop through all possible variable matches
    for (sregex_iterator i(expr.begin(), expr.end(), VarPattern); i != End; ++i) {
        string name = (*i)[0];

        // If it is a variable
        if (Vars.find(name) != Vars.end()) {
            sregex rgxName = sregex::compile("\\b" + name + "\\b");

            // Replace all occurrences of it
            newExpr = xpressive::regex_replace(
                newExpr, rgxName,
                lexical_cast<string,double>(Vars[name])
            );
        }
    }

    return newExpr;
}
于 2012-10-03T07:18:23.913 に答える