Подводя итог: Как я могу запретить моему шаблону регулярных выражений ошибочно принимать сегменты строк как имя переменной из целого слова? Это замена букв, которые являются частью большего слова, хотя я использую границы слов \b
,
Что я пытаюсь сделать: Я работаю над калькулятором. У него есть список переменных, и перед передачей выражения в парсер я вызываю свою функцию ParseVars()
сделать regex_search
используя шаблон для сопоставления переменных. Как только в нем есть все токены, соответствующие моему шаблону переменных, я проверяю, действительно ли эта строка находится в списке имен переменных, и если да, я заменяю строку значением переменной. Кроме того, каждый раз, когда в парсере производятся вычисления, я определяю константу с именем ans1
, ans2
, и так далее.
Проблема в: Допустим, у меня есть определенная переменная с именем 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
Разве это не должно соответствовать только целым словам? Граница слова работает хорошо, пока «а» не находится в другом месте строки. Может это мой 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
?
Ну, я нашел решение. Я помещаю свой ответ здесь для любого, кто столкнулся с подобной проблемой.
Проблема заключалась в том, что я использовал базовую замену строки ПОСЛЕ того, как сработало регулярное выражение, поэтому границы слов работали, просто функция замены строк заменяла все вхождения строки независимо от границ слов. Я должен использовать 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;
}
Других решений пока нет …