所以我的项目是创建一个程序,该程序接受类似于以下内容的输入:
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
所以这里的问题是,我的中缀流在两个字符串中,但在第3行,姓氏有两个部分,最后一行有一个名字。我需要另一种方法来获取这些名字。
顺便说一句,我目前正在学习C++入门课程,所以我的知识有限,但我毫不犹豫地进行研究。正如您所看到的,我正在使用更多的入门级代码。我试着使用数组,但我得出的结论是,我仍然不知道如何成功地传递它们。
您应该将输入字符串标记化,并实现稍微复杂一点的解析。您可以在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中,您可以使用regex包。
您需要更好的格式规范。这两个文件看起来都像固定宽度格式的文件。
带空格的名字占据前19个字符,等级从第20位开始,每个等级占据3个字符。
你可以玩这个。
这非常详细,但演示了迭代器的使用。我使用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
应该是微不足道的。
只是为了好玩,一个使用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.