2016-06-24 2 views
1

Мы получаем довольно необычную ошибку. Наша программа пытается вычислить производные с использованием регулярных выражений и рекурсии.C++ regex, передавая эквивалентные строковые параметры, но получая разные выходы

Из нашего ввода файла мы использовали регулярное выражение для определения правила производной, которое мы должны применить. Используя smatch, мы можем анализировать различные части нашего уравнения струны.

Наша ошибка появляется, когда наша программа пытается вычислить производную для «(x^2) + (x)». Smatch анализирует «x^2» и «x» из этого уравнения и рекурсивно вызывает производную функцию, используя эти две строки в качестве параметров. Однако в нашем выпуске отсутствует производная от «x».

Вход:

(x^2)+(x) 

Вызов:

return derivative(s[1].str()) + "+" + derivative(s[2].str()); 

Выход:

2x^1*1+ 

Однако, если мы пройдем:

return derivative(s[1].str()) + "+" + derivative("x"); 

Затем, выход становится:

2x^1*1+1 

Мы также проверили, если (с [2] .str() == "х"), и это верно. Почему мы получаем разные результаты с одного входа?

Equations.txt:

7 
x 
5x 
x^3 
(x^2)+(x) 

main.cpp:

#include <iostream> 
#include <fstream> 
#include <cmath> 
#include <queue> 
#include <stack> 
#include <regex> 
#include <vector> 
#include <iterator> 
#include <map> 
#include <string> 

using namespace std; 

/*****************************************************************/ 

class ReadFile 
{ 
private: 
    ifstream infile; 
    queue<string> input; 
public: 
    ReadFile(string filename) 
    { 
     infile.open(filename); 
     if(!infile) 
      cerr << "Unable to open file\n"; 
     string temp; 
     while(!infile.eof()) 
     { 
      getline(infile, temp); 
      input.push(temp); 
     } 
    } 
    string getFront() 
    { 
     string temp = input.front(); 
     input.pop(); 
     return temp; 
    } 
    bool isEmpty() { return input.empty(); } 
}; 

/*****************************************************************/ 

class Simplifier 
{ 
private: 
    string exp; 
public: 
    Simplifier(string ex): exp(ex) {} 

}; 

/*****************************************************************/ 


class ExpressionAnalyzer 
{ 
    string expression; 
    map<string, regex> rules; 
    smatch s; 
public: 
    ExpressionAnalyzer() 
    { 
     rules["con"] = "([[:d:]]+)"; 
     rules["xxx"] = "(x|\\(x\\))"; 
     rules["cof"] = "([[:d:]]+)(.*)"; 
     rules["pow"] = "(.*)[^]([[:d:]]+)"; 
     rules["add"] = "\\((.*)\\)[+]\\((.*)\\)"; 
    } 

    string derivative(string str) 
    { 
     s = generateSmatch(str); 
     if(regex_match(str, rules["con"])) 
      return "0"; 
     else if (regex_match(str, rules["xxx"])) 
      return "1"; 
     else if (regex_match(str, rules["cof"])) 
      return s[1].str() + "*" + derivative(s[2].str()); 
     else if (regex_match(str, rules["pow"])) 
      return s[2].str() + s[1].str() + "^" + to_string(stoi(s[2].str()) - 1) + "*" + derivative(s[1].str()); 
     else if (regex_match(str, rules["add"])) { 
      cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl; 
      return derivative(s[1].str()) + "+" + derivative(s[2].str());} 
     return ""; 
    } 

    smatch generateSmatch(string str) 
    { 
     smatch s; 
     map<string, regex>::iterator it; 
     for(it = rules.begin(); it != rules.end(); it++) 
     { 
      if(regex_match(str, s, it->second)) 
      { 
       return s; 
      } 
     } 
     return s; 
    } 
}; 

/*****************************************************************/ 

int main() 
{ 
    ReadFile test("Equations.txt"); 

    string s = test.getFront(); 
    ExpressionAnalyzer e; 
    cout << e.derivative(s) << endl; 

} 
+0

я не уверен, что актуальной проблемой является , но выполнение вашего кода на ideone дает следующие результаты: 'e.derivative (" (x) ")' возвращает '1' (что работает)' e.derivative ("(x^2)") 'возвращает пустую строку и 'e.derivative (" (x^2) + (x) ")' возвращает 1 + 1. Я думаю, что что-то с вашей рекурсией нарушено. Я бы предложил попробовать создать только конкретный smatch, который вам нужен внутри if, вместо того, чтобы перебирать все возможности, а затем использовать if. Я думаю, что это сделало бы ошибки более очевидными. – Anedar

+0

У меня разные результаты в зависимости от clang/gcc ... – Jarod42

ответ

0

Я все еще не уверен, что происходит именно здесь. Чтобы узнать больше, используйте отладчик, пройдите через вашу программу и проверьте каждую переменную после каждого шага. Или добавьте намного больше отладочного вывода, чтобы быть уверенным, что знаете, в какой точке рекурсии ваша программа терпит неудачу.

Однако, избавившись от цикла (и всей функции generateSmatch()), я смог заставить ваш код работать (почти, см. Ниже). Обратите внимание, что может быть более чистое решение, так как в if-выражении повторяется много кода, но этот работает, и я оставлю вас преувеличением. Также обратите внимание, что это может быть только частичное решение, так как я не тестировал часть загрузки файлов. Так что не забудьте избавиться от дополнительных \n и подобных перед вызовом этой функции.

#include <iostream> 
#include <fstream> 
#include <cmath> 
#include <queue> 
#include <stack> 
#include <regex> 
#include <vector> 
#include <iterator> 
#include <map> 
#include <string> 

using namespace std; 

/*****************************************************************/ 


class ExpressionAnalyzer 
{ 
    string expression; 
    map<string, regex> rules; 
public: 
    ExpressionAnalyzer() 
    { 
     rules["con"] = "([[:d:]]+)"; 
     rules["xxx"] = "(x|\\(x\\))"; 
     rules["cof"] = "([[:d:]]+)(.*)"; 
     rules["pow"] = "(.*)[^]([[:d:]]+)"; 
     rules["add"] = "\\((.*)\\)[+]\\((.*)\\)"; 
    } 

    string derivative(string str) 
    { 
     cout << "call with: " << str << endl; 
     if(regex_match(str, rules["con"])){ 
      cout << "const!" << endl; 
      return "0"; 
      } 
     else if (regex_match(str, rules["xxx"])){ 
      cout << "xxx!" << endl; 
      return "1"; 
     } 
     else if (regex_match(str, rules["cof"])){ 
      cout << "cof!" << endl; 
      smatch s; 
      regex_match(str, s, rules["cof"]); 
      cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl; 
      return s[1].str() + "*" + derivative(s[2].str()); 
      } 
     else if (regex_match(str, rules["pow"])){ 
      cout << "pow!" << endl; 
      smatch s; 
      regex_match(str, s, rules["pow"]); 
      cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl; 
      return s[2].str() + s[1].str() + "^" + to_string(stoi(s[2].str()) - 1) + "*" + derivative(s[1].str()); 
     } 
     else if (regex_match(str, rules["add"])) { 
      cout << "add!" << endl; 
      smatch s; 
      regex_match(str, s, rules["add"]); 
      cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl; 
      return derivative(s[1].str()) + "+" + derivative(s[2].str());} 
     else{ 
      cout << "not recognized!" << endl; 
      return ""; 
     } 
    } 

}; 

/*****************************************************************/ 

int main() 
{ 
    ExpressionAnalyzer e; 
    cout << e.derivative("(x)") << endl; 
    cout << e.derivative("(x^2)") << endl; 
    cout << e.derivative("x^2") << endl; 
    cout << e.derivative("(x^2)+(x)") << endl; 

} 

Выход:

call with: (x) 
xxx! 
1      <-result 
call with: (x^2) 
not recognized! 
         <-result (parantheses were not simplified away yet) 
call with: x^2 
pow! 
s[1]: x, s[2]: 2 
call with: x   <- recursion 
xxx! 
2x^1*1     <-result (without parantheses: working) 
call with: (x^2)+(x) 
add! 
s[1]: x^2, s[2]: x 
call with: x   <- recursion 
xxx! 
call with: x^2   <- recursion 
pow! 
s[1]: x, s[2]: 2 
call with: x   <- recursion lvl 2 
xxx! 
2x^1*1+1    <- result (YAY!) 

Я оставил отладочный-вывод на цели, может быть, это помогает увидеть, что иногда более подробный вывод помогает увидеть, что происходит внутри.

0

s является членом, и в вашем рекурсивной fonction изменить его

s = generateSmatch(str); 

Включите его в качестве локальной переменной, чтобы получить ожидаемый результат:

string derivative(string str) 
{ 
    smatch s; 
    if(regex_match(str, s, rules["con"])) 
     return "0"; 
    else if (regex_match(str, s, rules["xxx"])) 
     return "1"; 
    else if (regex_match(str, s, rules["cof"])) 
     return s[1].str() + "*" + derivative(s[2].str()); 
    else if (regex_match(str, s, rules["pow"])) 
     return s[2].str() + s[1].str() + "^" + to_string(stoi(s[2].str()) - 1) + "*" + derivative(s[1].str()); 
    else if (regex_match(str, s, rules["add"])) { 
     cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl; 
     return derivative(s[1].str()) + "+" + derivative(s[2].str());} 
    return ""; 
} 
Смежные вопросы