2013-11-22 51 views
0

所以我的計劃是採取建立一個程序,它看起來類似於這樣的輸入:我需要一個替代方法來串流字符串。 C++

Boole, George  98 105 -1 -1 -1 
Pascal, Blaise  63 48 92 92 92 
Babbage, Charles 100 97 100 98 -1 
Kepler, Johannes 75 102 100 -1 -1 
Clown, Bozo   0 6 6 57 62 
Fini, End   -99 -99 -99 -99 -99 

和輸出這樣的:我有麻煩

Student   Submission  Grade 
Boole, George  2   105 
Pascal, Blaise  3   92 
Babbage, Charles 1   100 
Kepler, Johannes 2   102 
Clown, Bozo   5   62 

,因爲我現在的代碼可以成功編譯它,但我的其他輸入文件之一遵循不同的格式。我當前的代碼:

int main() 
{ 

    ifstream infile; 
    ofstream outfile; 
    infile.open("./ProgGrades1.txt"); 
    outfile.open("./GradeReporttest.txt"); 

    string lastName, firstName; 

    int score1, score2, score3, score4, score5; 
    int max, location; 

    while(GetInput(infile, lastName, firstName, score1, score2, score3, score4, 
      score5)) 
    { 
     if (score1 == -99) 
      break; 
     AnalyzeGrade(infile, lastName, firstName, score1, score2, score3, 
       score4, score5, max, location); 

     WriteOutput(infile, outfile, lastName, firstName, max, location); 

     cout << lastName << " " << firstName << " " << location << " " << max << 
       endl; 
    } 

    infile.close(); 
    outfile.close(); 
    return 0; 
} 

int GetInput(ifstream& infile, string& lastName, string& firstName, int& score1, 
     int& score2, int& score3, int& score4, int& score5) 
{ 
    infile >> lastName >> firstName >> score1 >> score2 >> score3 >> 
      score4 >> score5; 
    return infile; 
} 


int AnalyzeGrade(ifstream& infile, string& lastName, string& firstName, 
     int& score1, int& score2, int& score3, int& score4, int& score5, 
     int& max, int& location) 
{ 
    int score[5]; 
    max = 0; 
    score[0] = score1; 
    score[1] = score2; 
    score[2] = score3; 
    score[3] = score4; 
    score[4] = score5; 

    for (int i = 0; i < 5; i++) 
    { 
     if (score[i] > max) 
     { 
      max = score[i]; 
     } 
    } 

    if (max == score[0]) 
    { 
     location = 1; 
    } 
    else if (max == score[1]) 
    { 
     location = 2; 
    } 
    else if (max == score[2]) 
    { 
     location = 3; 
    } 
    else if (max == score[3]) 
    { 
     location = 4; 
    } 
    else if (max == score[4]) 
    { 
     location = 5; 
    } 
    else 
    { 

    } 

    fill_n(score, 6, 0); 
    return infile; 
} 

void WriteOutput(ifstream& infile, ofstream& outfile, string& lastName, 
     string& firstName, int& max, int& location) 
{ 
    string studentID = lastName + " " + firstName; 
    outfile << "\n" << setw(19) << studentID << setw(14) << location << " " << 
      max; 
} 

我的其他輸入文件看起來像:

Stroustrup, Bjarne 8 8 -1 -1 -1 
Lovelace, Ada  1 60 14 43 -1 
von Neumann, Jon 77 48 65 -1 -1 
Wirth, Niklaus  51 59 -1 -1 -1 
Wozniak, Steve  81 -1 -1 -1 -1 
Babbage, Charles 31 92 -1 -1 -1 
Hopper, Grace  76 -1 -1 -1 -1 
Bird, Tweety  -99 -99 -99 -99 -99 
Sylvester   77 39 -1 -1 -1 

所以這裏的問題是,在兩個字符串我INFILE流,但在第3行有兩個部分姓氏,最後一行有一個名字。我需要一種替代方法來獲取名稱。

btw我目前在C++課程介紹,所以我的知識是有限的,但我沒有任何疑慮研究。正如你所看到的,我正在使用更多的入門級代碼。我試圖使用數組,但我的結論是,我仍然不明白如何成功傳遞它們。

+0

我的代碼基本上達到了同樣的結論。使用變量lastName和firstName,我可以獲取整個名稱並將其輸出爲一個字符串。第3行有逗號,但姓氏有兩個部分,所以會混亂。 – hanipman

+0

'std :: getline(infile,',')'將提取所有內容到第一個逗號並放棄逗號。也許你可以使用它。 –

+0

這對於第三行是有效的,但不是最後一行,因爲沒有逗號需要停下來。 – hanipman

回答

1

你應該標記輸入字符串並實現稍微更復雜的解析。你可以在你的GetInput函數中使用boost :: split,或者只使用strtok函數。像這樣:

int GetInput(ifstream& infile, string& lastName, string& firstName, int& score1, 
     int& score2, int& score3, int& score4, int& score5) 
{ 
    std::string line = infile.str(); 
    std::list<std::string> tokens; // or something fancy with boost::iterator_range 

    boost::split (tokens, line, boost::is_any_of(",")); // define your own predicate if needed 
    // check result and tokens collection before processing it 
    std::list<std::string>::iterator it = tokens.begin(); 
    lastName.swap(*it++); 
    // now you should split rightmost token the same way but with space between tokens... 

    return infile; 
} 

但是正確的解決方案將嘗試正則表達式。在C++ 11世界中,您可以使用正則表達式包。

1

您需要更好的格式規格。這兩個文件看起來都是固定寬度格式的文件。

帶空格的名字佔據前19個字符,等級從第20位開始,每個等級佔3個字符。

你可以玩那個。

0

這是非常詳細的,但演示了迭代器的使用。爲了說明的目的,我使用了stringstream。刪除, John以查看它如何處理沒有名字。

請注意,我從這裏獲取trim,但不要在此處發佈代碼以簡化操作。

#include <iostream> 
#include <string> 
#include <sstream> 
#include <algorithm> 
#include <cctype> 

int main() { 
    std::string line = "von Neumann, John 77 48 65 -1 -1"; 
    std::istringstream iss(line); 
    auto it = std::find(line.begin(), line.end(), ','); 
    std::string last_name; 
    std::string first_name; 
    std::string integer_list; 

    // If we didn't find a comma 
    if (it == line.end()) 
    { 
     // We have a last name only 
     first_name = "NO_FIRST_NAME"; 
     // No comma, so we just search up to the first integer 
     auto find_integer_it = std::find_if(line.begin(), line.end(), [] (char c) { return isdigit(c); }); 
     last_name = std::string(line.begin(), find_integer_it); 
     // Get rest of string from the position of first integer 
     integer_list = std::string(find_integer_it, line.end()); 
     trim(last_name); 
    } else { 
    last_name = std::string(line.begin(), it); 

    // it+2 because we're skipping the comma 
    // and the whitespace after the comma 
    auto space_it = std::find(it+2, line.end(), ' '); 
    first_name = std::string(it+2, space_it); 
    auto find_integer_it = std::find_if(line.begin(), line.end(), [] (char c) { return isdigit(c); }); 
    integer_list = std::string(find_integer_it, line.end()); 
    } 
    std::cout << last_name << ", " << first_name << std::endl; 
    std::cout << integer_list << std::endl; 
} 

輸出:

von Neumann, John 

77 48 65 -1 -1 

在這一點上,它應該是微不足道的解析integer_list

0

只是爲了好玩,一個使用boost::spirit來完成這項工作的程序。處理字符串肯定有更清晰的方式。

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/home/phoenix/object/construct.hpp> 
#include <boost/spirit/home/phoenix/container.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/optional.hpp> 
#include <iostream> 
#include <fstream> 
#include <string> 
#include <vector> 

struct Student 
{ 
    boost::optional<std::string> first_name; 
    std::string last_name; 
    std::vector<signed long> grades; 

    bool fill(const std::string& str) 
    { 
     namespace qi = boost::spirit::qi; 
     namespace ascii = boost::spirit::ascii; 
     namespace phoenix = boost::phoenix; 

     typedef std::vector<char> chars; 
     auto set_last_name = 
      [this](const std::vector<char>& name) 
      { 
       last_name = std::string(name.begin(), name.end()); 
      }; 
     auto set_first_name = 
      [this](const std::vector<char>& name) 
      { 
       first_name = std::string(name.begin(), name.end()); 
      }; 

     bool r = qi::phrase_parse(str.begin(), str.end(), 
      (
       (+qi::alpha)[ set_last_name ] // gives vector of char 
       >> -(',' >> +qi::alpha)[ set_first_name ] // gives vector of char 
       >> *(qi::int_ [ phoenix::push_back(phoenix::ref(grades), qi::_1) ]) 
      ), qi::space);  

     return r; 
    } 
}; 


int main(int argc, char* argv[]) 
{  
    if (argc < 2) 
    { 
     std::cout << "Please specify a filename" << std::endl; 
     return -1; 
    } 

    std::ifstream file(argv[1]); 

    if (!file) 
    { 
     std::cout << "Invalid filename: " << argv[1] << std::endl; 
     return -2; 
    } 

    std::vector<Student> students; 
    std::string str; 
    while (getline(file, str)) 
    {  
     Student student; 
     if (student.fill(str)) 
     { 
      std::cout << "Parsing succeeded, adding '" ; 

      if (student.first_name) 
      { 
       std::cout << *student.first_name << " "; 
      } 

      std::cout 
       << student.last_name 
       << "' with " << student.grades.size() << " grades." 
       << std::endl; 
      students.push_back(student); 
     } 
     else 
     { 
      std::cout << "Parsing failed." << std::endl; 
     } 
    } 

    return 0; 
} 

這裏是輸出:

$ ./a.exe input.txt 
Parsing succeeded, adding 'Bjarne Stroustrup' with 5 grades. 
Parsing succeeded, adding 'Ada Lovelace' with 5 grades. 
Parsing succeeded, adding 'Jon vonNeumann' with 5 grades. 
Parsing succeeded, adding 'Niklaus Wirth' with 5 grades. 
Parsing succeeded, adding 'Steve Wozniak' with 5 grades. 
Parsing succeeded, adding 'Charles Babbage' with 5 grades. 
Parsing succeeded, adding 'Grace Hopper' with 5 grades. 
Parsing succeeded, adding 'Tweety Bird' with 5 grades. 
Parsing succeeded, adding 'Sylvester' with 5 grades.