I am working on a project for a class at school. It is a simple implementation of stacks and queues. However as part of the project we are require to read opcode in from a file. The opcode is formated as follows:
append 10
serve
append 20
append 30
serve
push 10
push 50
push 20
push 20
pop
My problem is when I read in the file through a standard fstream it seems to pick up some kind of weird formatting or something, and won't match comparison checks.
I am wonder what I am doing wrong, how to fix it, and if there is a better way to manipulate opcode going forward. As it is, the if-else statement always goes to if. Kind of desperately need to get this working.
#include "StackAndQueue.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
int main(){
Stack leStack;
Queue leQueue;
//Read in the datafile.
cout << "Reading default file: p2datafile.txt";
fstream data("p2datafile.txt");
while (data.fail()){
cout << " failed." << endl;
data.close();
cout << "Please enter path to datafile: ";
string filename;
cin >> filename;
data.open(filename.c_str());
}
cout << endl << "Sucess!" << endl;
//Loop through all the commands in the file
while(!data.eof()){
// Determine what kind of command is running
// and if parsing will be needed.
string opcode;
getline(data,opcode,' ');
if (opcode == "pop"){
cout << "popping!" << endl;
leStack.pop();
}
else if (opcode == "serve"){
cout << "serving" << endl;
leQueue.serve();
}
else if (opcode == "push"){
cout << "pushing";
}
else{
cout << "else!" << endl;
}
}
data.close();
system("pause");
return 0;
}
开发者_开发知识库
I apologize if the code is difficult to read, and the general half-finished nature of it. I am still pretty new to this.
getline
used in that way considers just ' '
as a delimiter, so it won't stop at newlines; moreover, you're not extracting the argument (when the opcodes has any), so it will get read as an opcode (sticked in front of the real opcode) at the next iteration.
In my opinion, you could simply get away with using just the normal operator>>
. It stops correctly at any whitespace (which is what you want to do) and supports the C++ strings correctly. The important thing is to remember to extract also the argument when needed (again, with operator>>
), watching for istream::fail()
errors in case of bad number formatting. You may even want to have the stream rise exceptions in case of these errors (so they don't go unnoticed).
try
{
string opcode;
data.exceptions(ios::failbit);
//Loop through all the commands in the file
while(data>>opcode){
// Determine what kind of command is running
// and if parsing will be needed.
int argument;
if (opcode == "pop"){
cout << "popping!" << endl;
leStack.pop();
}
else if (opcode == "serve"){
cout << "serving" << endl;
leQueue.serve();
}
else if (opcode == "push"){
cout << "pushing";
data >> argument;
}
else if (opcode == "append"){
cout << "appending";
data >> argument;
}
else{
cout << "else!" << endl;
}
}
data.close();
}
catch(const ios::failure & ex)
{
if(!data.eof())
cout<<"IO error"<<endl;
}
the problem you are most likely having stems from the way you are reading input. std::getline(..., ' ')
extracts a string that ends with a space. With the given input, the first string gotten will be append
, but the second will be
10
serve
append
because there are no spaces.
How about this, instead of trying to read in an opcode exactly, read a line, and see if you can figure out if it begins with an opcode.
Rather than reading the file a word a a time, read the entire line (using std::getline
) then use a std::stringstream
to process the line, something like this:
std::string line;
while(std::getline(file,line))
{
std::stringstream linestream(std::stringstream::in|std::stringstream::out);
linestream << line;
std::string command;
if(std::getline(linestream,command,' '))
{
//process line - chain 'if(std::getline(linestream,command,' '))' to advance the token steam
}
else
//error blank line
}
精彩评论