正则表达式 - 词边界失败

时间:2012-10-03 06:25:25

标签: c++ regex boost match word-boundary

总结:如何防止我的正则表达式模式将字符串片段误认为是一个全字变量名?即使我使用单词边界\b,它也会取代作为更大单词一部分的字母。

我想做什么:我正在研究计算器。它有一个变量列表,在将表达式传递给解析器之前,我调用我的函数ParseVars()来使用变量匹配模式进行regex_search。一旦它具有与我的变量模式匹配的所有标记,我检查该字符串是否实际上在变量名称列表中,如果是,我用变量值替换该字符串。此外,每次在解析器中进行计算时,我都会定义一个名为ans1ans2的常量,依此类推。

问题是:假设我定义了一个名为a的变量,其值为6。 (顺便说一句,我在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+6而不是ans1+6

1 个答案:

答案 0 :(得分: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;
}