2011-10-16 31 views
1

我需要在開始時讀取多行使用特定關鍵字。 我有一個基本問題,我需要一隻手來幫助我。讀取多行,但特別是...有效地解析它們

這裏有類型的輸入:

關鍵字1 0.0 0.0
關鍵字1 1.0 5.0
關鍵字2 10.0
KEYWORD3 0.5
keyword4 6.0

規則是:

  • 包含關鍵字1的行& keyword2應該按照該順序並且在任何其他行之前。含有KEYWORD3 & keyword4

  • 線可以是任何順序

  • 關鍵字1必須被隨後2雙

  • 關鍵字2,3 & 4必須隨後用1雙

  • 在一行包含所有四個關鍵字並緊接着它們的double的行的結尾處,「循環」斷開並且觸發計算。

這裏的來源,我有:

using namespace std; 

int main (int argc, const char * argv[]) {  
    vector<double> arrayInputs; 
    string line; 
    double keyword1_first, keyword1_second, keyword4, 
      keyword3, keyword2; 
    bool inside_keyword1=false, after_keyword2=false, 
      keyword4_defined=false, keyword3_defined=false ; 

//cin.ignore(); 

while (getline(cin, line)) { 
    if (inside_keyword1 && after_keyword2 && keyword3 && keyword4) { 
     break; 
    } 
    else 
    { 
     std::istringstream split(line); 
     std::vector<std::string> tokens; 
     char split_char = ' '; 
     for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)); 

     if (tokens.size() > 2) 
     { 
      if (tokens[0] != "keyword1") return EXIT_FAILURE; // input format error 
      else 
      { 
       keyword1_first = atof(tokens[1].c_str()); 
       keyword1_second = atof(tokens[2].c_str()); 

       inside_keyword1 = true; 
      } 
     } 
     else 
     { 
      if (tokens[0] == "keyword2") 
      { 
       if (inside_keyword1) 
       { 
        keyword2 = atof(tokens[1].c_str()); 
        after_keyword2 = true; 
       } 

       else return EXIT_FAILURE; // cannot define anything else keyword2 after keyword1 definition 

      } 
      else if (tokens[0] == "keyword3") 
      { 
       if (inside_keyword1 && after_keyword2) 
       { 
        keyword3 = atof(tokens[1].c_str()); 
        keyword3_defined = true; 
       } 
       else return EXIT_FAILURE; // cannot define keyword3 outside a keyword1 
      } 
      else if (tokens[0] == "keyword4") 
      { 
       if (inside_keyword1 && after_keyword2) 
       { 
        keyword4 = atof(tokens[1].c_str()); 
        keyword4_defined = true; 
       } 
       else return EXIT_FAILURE; // cannot define keyword4 outside a keyword1 
      } 
     } 
    } 
} 

// Calculation 


// output 


return EXIT_SUCCESS; 
} 

我的問題是:有沒有更有效的方法去了解這個除了使用布爾在讀/解析循環?

+3

那麼,有什麼問題呢? – Thomas

+0

你定義了你的「問題」(儘可能多的你已經制定了一項任務或任務),並且你提供了源,但是對於你沒有爲我們指出*問題的讀者。你的問題是什麼? – HostileFork

+0

我很抱歉。問題是:它是否存在另一種更有效的方式,而不是在讀/解析循環中使用布爾值? – gluon

回答

2

你問一些「更高效」的東西,但是看起來你沒有一個特定的性能目標。所以你在這裏想要的可能更像是一個代碼審查。有一個網站,在特定的:

https://codereview.stackexchange.com/

但無論如何...

你是正確的直覺四個布爾是不是真的要求在這裏。那是2^4 = 16個不同的「狀態」,其中許多你永遠都不應該去。 (您的規格明確禁止,例如,keyword3_defined == trueafter_keyword1 == false)。

當然,程序狀態可以保存在枚舉和布爾值。這使得「健忘」循環可以在不同情況下重新訪問一行代碼,但仍然記得它處於什麼階段。在許多情況下,包括複雜的解析器中,它都很有用。但是,如果你的任務是線性和簡單的,最好基於已達到某一行代碼而隱式「知道」狀態。

作爲教育爲例,說明我談論的對比,這裏只是一個狀態機的後跟任意數量的字母B s的信A閱讀:

enum State { 
    beforeReadingAnA, 
    haveReadAnA, 
    readingSomeBs, 
    doneReadingSomeBs 
}; 

State s = beforeReadingAnA; 
char c; 
while(true) { 
    switch (s) { 
     case beforeReadingAnA: 
      cin >> c; 
      if (cin.good() && c == 'A') { 
       // good! accept and state transition to start reading Bs... 
       s = haveReadAnA; 
      } else { 
       // ERROR: expected an A 
       return EXIT_CODE_FAILURE; 
      }; 
      break; 

     case haveReadAnA: 
      // We've read an A, so state transition into reading Bs 
      s = readingSomeBs; 
      break; 

     case readingSomeBs: 
      cin >> c; 
      if (cin.good() && c == 'B') { 
       // good! stay in the readingSomeBs state 
      } else if (cin.eof()) { 
       // reached the end of the input after 0 or more Bs 
       s = doneReadingSomeBs; 
      } else { 
       // ERROR: expected a B or the EOF 
       return EXIT_CODE_FAILURE; 
      } 
      break; 

     case doneReadingSomeBs: 
      // all done! 
      return EXIT_CODE_SUCCESS; 
    } 
} 

如前所述,這是一個風格可以是非常非常有用的編碼。然而,對於這種情況,這是荒謬的。與做同樣的事情的簡單線性代碼段比較:

// beforeReadingAnA is IMPLICIT 

char c; 
cin >> c; 
if (cin.fail() || c != 'A') 
    return EXIT_CODE_FAILURE; 

// haveReadAnA is IMPLICIT 

do { 
    // readingSomeBs is IMPLICIT 

    cin >> c; 
    if (cin.eof()) 
     return EXIT_CODE_SUCCESS; 
    if (cin.fail() || c != 'B') 
     return EXIT_CODE_FAILURE; 
} 

// doneReadingSomeBs is IMPLICIT 

所有狀態變量消失。它們是不必要的,因爲程序只是「知道它在哪裏」。如果你重新思考你的例子,那麼你也可以做同樣的事情。您不需要四個布爾值,因爲您可以將光標放在一行代碼上並自信地說,如果該行代碼恰好在運行,那麼這四個布爾值必須是

至於效率高一尺,<iostream>類可以使生活更輕鬆比你在這裏和更地道的C++,而不調用C-主義像atof或永遠不必使用c_str()。讓我們看一下你的代碼的簡單摘錄,它只讀取與「keyword1」關聯的雙打。

string line; 
getline(cin, line); 
istringstream split(line); 
vector<string> tokens; 
char split_char = ' '; 
string each; 
while (getline(split, each, split_char)) { 
    tokens.push_back(each); 
} 
double keyword1_first, keyword1_second; 
if (tokens.size() > 2) { 
    if (tokens[0] != "keyword1") { 
     return EXIT_FAILURE; // input format error 
    } else { 
     keyword1_first = atof(tokens[1].c_str()); 
     keyword1_second = atof(tokens[2].c_str()); 
    } 
} 

對比度與此:

string keyword; 
cin >> keyword; 
if (keyword != "keyword1") { 
    return EXIT_FAILURE; 
} 
double keyword1_first, keyword1_second; 
cin >> keyword1_first >> keyword1_second; 

魔術。 Iostreams可以檢測您正在嘗試讀取或寫入的類型。如果遇到問題以您要求的方式解釋輸入,那麼它會將輸入留在緩衝區中,以便您可以嘗試另一種方式讀取它。 (在詢問字符串的情況下,行爲是讀取一系列字符,直到空白字符...如果您確實需要整行,則可以使用getline

錯誤處理是你必須處理的事情,但是。可以告訴iostream使用異常處理方法,以便遇到問題的標準響應(例如,在預期爲double的地方使用隨機單詞)會導致程序崩潰。但默認是設置,你需要測試失敗的標誌:

cin erratic behaviour

有細微差別的iostream,所以你可能想要做Q & A的一些調查......我一直在學習位自己最近在回答/詢問這裏:

Output error when input isn't a number. C++

When to use printf/scanf vs cout/cin?

+0

我必須非常感謝你,HostileFork。對於我問這個問題的方式,我感到非常抱歉。我正在學習如何在這裏使用/分享/討論......關於這些概念,我非常感謝你。我會在明天嘗試在那段代碼中實現enum和iostream。我會告訴你。最好的問候,J. – gluon

+0

當然...很高興幫助那些正在尋求改進他們的代碼和方法的人。 (很多人只是不在乎問。)但很快這將是你的機會去解釋這個東西給別人! :)請記住,我的觀點的一部分與方法的對比是,您可能不需要此特定程序的枚舉。儘量讓你的程序「知道它在哪裏」,並只在需要時才引入狀態。 – HostileFork

+0

全部實施。不是最好的方式,但它應該工作。現在我有一個seg故障11 ..跟蹤那個。我不知道我沒有正確分配內存。 – gluon

相關問題