C++ class member function error/exception handling during execution - c++

I have an assignment that to create a C++ Tokenizer class with one public method
vector *GetTokens ( void );
The function takes a string in via stdin, tokenizes the string, and returns a vector pointer of the tokens either of size ()=1 or 2. The function needs to throw errors when: there are 0 tokens, more than 2 tokens, when the first token is not a String, or when the first token is not a String and the second is not an Integer.
Code that calls my function from professor:
//////////////////////
For (int i=0; i <5; i++) {
Tokenizer tok;
Vector<string> *test = tok.GetTokens ();
If (test->size ()==1) {
cout << "Yay" << endl;
} else {
cout << "Boo" << endl;
}
///////////////
I have been able to successfully complete this program for proper tokenization. I am also to print out the errors via if...then statements. However, during my errors, the cout << "Yay" or "Boo" still prints out. I need to instead not have this text print out while still allowing the for loop/calling function continue execution.
Is there a way, to use exceptions or errors with asserts in my GetTokens () method to essentially stop execution, print my error text, pass control back to the calling function without printing out any additional text and progress to the next loop cycle?
::::EDIT::::
My Tokenizer.cpp
///////////////////
'//Constructor
Tokenizer::Tokenizer( void ) { }
//This includes my tokenization with my error/exception handling
vector<string> * Tokenizer::GetTokens() {
string strIN;
cout << "> ";
getline(cin, strIN);
vector<string> *tokens = atokenizer(strIN);
//So with one of my constraints, I need to print an error for 0 tokens
try{
if(tokens->size()!=0) {
return tokens;
} else {
throw tokens;
}
}
catch(vector<string> *error) {
cout << "ERROR!" << endl;
return error;
}
}
//This is my tokenization function which parses by whitespace
vector<string> *Tokenizer::atokenizer(string strIN) {
vector<string> *tokens = new vector<string>();
string token="";
int c=0;
bool whiteSpace=true;
//Iterates thru all chars and tokenizes by " "
for(int i=0; i<strIN.size(); i++) {
//Checks if char==1-0,a-z,etc. or is space=" "
if((strIN[i]>=33) && (strIN[i]<=126)) {
//If char, appends to token
token+=strIN[i];
whiteSpace=false;
}
else if((strIN[i]==32) && (whiteSpace==false)) {
//If space, adds token to tokens
tokens->push_back(token);
token="";
c++;
whiteSpace=true;
}
}
//Adds final token
if(token!="") {
tokens->push_back(token);
}
return tokens;
}'
//////////////////

So I figured a different way to solve my question. I couldn't get any of the error handling or exceptions to work. Instead, I just went back to using If...then...else statements to do error checking with cout and then I created functions to control the printout.
void coutOff() {
cout.setstate(std::ios_base::failbit)
}
void coutOn() {
cout.clear();
}

Related

Infile stops reading command line arguments

**Edit: As it turns out, it was a simple typo under the if(i==0) statement. I missed putting {} to enclose both first_nonterminal statements.
I'm creating a CFG for an assignment, but I've gotten stuck. My program is supposed to read a file (of strings) by getting the file name from the command line, and then do certain things with the contents of the file.
using namespace std;
string current, first_nonterminal;
int main(int argc, char *argv[])
{
if(argc != 2)
{
std::cout << "No file name given" << std::endl; // if there is no file name in command line
exit(1);
}
ifstream infile(argv[1]);
if(!infile)
{
std::cout << "Given file " << argv[1] << " will not open."; // if file refuses to open
exit(2);
}
string word;
for(int i = 0; infile >> word; ++i)
{
cout << word << endl; // (debug) print input word
try // check if first word is in correct format
{
if (i == 0 && word.find(':') == string::npos) // check only first word,
{
throw runtime_error("File does not have correct format.");
}
}
catch(runtime_error &e)
{
cout << "Error:" << e.what();
exit(3);
}
if (i==0)
first_nonterminal = word;
first_nonterminal.pop_back(); // remove colon
insert(word); //put string through insert() method
}
randomize(); // randomize and replace
print(); // print end result
infile.close();
}
The above code intakes a file which is formatted like so:
STMT: THIS THAT OTHER
THIS: That carpet
THIS: Atlanta
THAT: is wild
OTHER: .
OTHER: , oooh OTHER2
OTHER2: oooh OTHER2
OTHER2: !
Any word that has a colon following it is considered a nonterminal, with the words following it considered terminals. Regardless, I've figured out the issue isn't my randomize() or insert() functions, as they work perfectly if I hard-code the file into the program. My issue is the file stops being read after a certain number of strings, and I'm not sure why. For example, when I put the above's file name into the command line, it runs through, but then after it puts "That" into the insert() function, it prints "carpet" via the debug cout, and then stops.

(C++) How to check whether or not an input string is an integer?

I want this code to check whether the input is an int or not, and it works fine until I enter a float type number. I need a program that won't let through float numbers.
bool error;
int x;
string s;
do
{
cout <<"number: ";
cin >> x;
error=cin.fail();
if(error)
{
cout << "error" <<endl;
cin.clear();
}
getline(cin,s);
}while(error);
cout << x;
Read in all of the user's input line as a string, then convert the string to an integer with std::stoi.
Unfortunately std::stoi will happily stop converting when it hits the end of convertible characters, but it allows you to pass in a pointer to a position to be updated with the character that ended the conversion. If this position is not the end of the string, there was garbage on the line.
bool error = true; // assume user input is wrong
while (error)
{
if (std::getline(std::cin, s)) // grab the whole line
{
std::size_t end;
try
{
x = std::stoi(s, &end);
if (end == s.length()) // converted all user input
{
error == false; // good data
}
}
catch(std::invalid_argument &) // user input is complete garbage
{
}
catch(std::std::out_of_range &) // converted user input is too big for int.
{
}
}
}
^
I recommend turning the input loop into a function. 1) It's easily reusable should you need to convert an int again. 2) It gets rid of some of the logic above because you can return when the input is tested and good.
int gimmieInt(std::istream& in) // Me eat input stream! Om nom nom nom!
{
std::string s;
int x;
while (true) // consider instead using a maximum number of retries.
// This increases complexity, so consider it *after* you have
// the basic version working
{
if (std::getline(in, s))
{
std::size_t end;
try
{
x = std::stoi(s, &end);
if (end == s.length())
{
return x;
}
}
catch(std::invalid_argument &) // user input is complete garbage
{
}
catch(std::std::out_of_range &) // user input is too big for int.
{
}
}
}
}
std::istream& operator(std::istream&, int) will read a valid integer number up to any non matching character like '.', and no error state is set for the stream up to this point.
You better should read complete (whitespace separeated) chunks as std::string, and inspect them if these contain the desired format (e.g. using std::regex).
std::stoi() should also fail with an exception, if you're trying to convert the chunk.
I think, you are looking for something like this (C++11):
auto s = std::string{};
std::cin >> s;
if( std::all_of(std::begin(s), std::end(s),
[](char c) -> bool {
return c <= '0' && c <= '9';
}) ) {
std::cout << "you have entered an integer" << std::endl;
}
Somehow I thought, that the standard library contains a predicate that checks if a given char is a digit, but I could not find it now. Such a hypothetic is_digit() would allow make the code more readable:
if( std::all_of(std::begin(s), std::end(s), std::hypothetic::is_digit) ) {
std::cout << "you have entered an integer" << std::endl;
}

Detect last line of file C++

I've been working on some code for a file parser function to learn some C++:
It's supposed to read in this text file:
>FirstSeq
AAAAAAAAAAAAAA
BBBBBBBBBBBBBB
>SecondSeq
TTTTTTTTTTTTTT
>ThirdSequence
CCCCCCCCCCCCCC
>FourthSequence
GGGGGGGGGGGGGG
and print out the names (lines with '>' at the start) and then the sequences.
However from the output:
AAAAAAAAAAAAAABBBBBBBBBBBBBB
TTTTTTTTTTTTTT
CCCCCCCCCCCCCC
FirstSeq
SecondSeq
ThirdSequence
FourthSequence
We see that the final line of G characters is not included. The code is below. What it does is loop over lines, if it finds a name, appends it to the vector of names, if it finds a sequence, appends it to a temporary string (incase the sequence is more than one line, like the first sequence), then when it finds the name of the next sequence, stores the built up temporary string in a vector and then proceeds by overwriting the temporary string and starting again. I suspect that it is because in the while loop of the function: The line fullSequence.push_back(currentSeq); which is called whenever a new name was detected previously to push the old temp string onto the vector would not be called for the last line of G's and so it is not being included, although the name "FourthSeq" is recorded, rather the line of G's is read into the temporary string, but then is not passed to the vector. So, how can I make it so as I can detect that this is the last line of the file and so should make sure the temporary string is pushed onto the vector?
Thanks,
Ben.
CODE:
#include<fstream>
#include<iostream>
#include<string>
#include<vector>
void fastaRead(string fileName)
{
ifstream inputFile;
inputFile.open(fileName);
if (inputFile.is_open()) {
vector<string> fullSequence, sequenceNames;
string currentSeq;
string line;
bool newseq = false;
bool firstseq = true;
cout << "Reading Sequence" << endl;
while (getline(inputFile, line))
{
if (line[0] == '>') {
sequenceNames.push_back(line.substr(1,line.size()));
newseq = true;
} else {
if (newseq == true) {
if(firstseq == false){
fullSequence.push_back(currentSeq);
} else {
firstseq = false;
}
currentSeq = line;
newseq = false;
} else {
currentSeq.append(line);
}
}
}
//Report back the sequences and the sequence names...
for ( vector<string>::iterator i = fullSequence.begin(); i != fullSequence.end(); i++) {
cout << *i << endl;
}
for ( vector<string>::iterator i = sequenceNames.begin(); i != sequenceNames.end(); i++) {
cout << *i << endl;
}
cout << fullSequence.size() << endl;
cout << sequenceNames.size() << endl;
inputFile.close();
} else {
perror("error whilst reading this file");
}
if(inputFile.bad()){
perror("error whilst reading this file");
}
}
int main()
{
cout << "Fasta Sequence Filepath" << endl;
string input = "boop.txt";
fastaRead(input);
return 0;
}
Getline() will "fail" when it finds an EOF in the line, so the last line you read will not go through your loop.
I've solved this problem two ways, either by having two flags or just by processing the last line after the loop.
For two flags, the loop requires both to be true, you set one to false when getline() fails, and you set the other one to false if the first one is false, this gives you one extra loop after EOF.
Good luck!

getline() method no instance of overloaded function

I am having some problem when trying to do classes for C++. This is my header file.h:
#include <iostream>
#include <string>
#ifndef MESSAGES__H__
#define MESSAGES__H__
class Message
{
public:
Message(std::string recipient, std::string sender);
void append(std::string text);
std::string to_string() const;
void print() const;
private:
std::string recipient;
std::string sender;
std::string message;
std::string text_input;
char* timestamp;
};
#endif
And when I run the main method, the getline(cin,) is giving me some error message:
int main()
{
vector <Message*> message_list;
Message* message1 = new Message("Student1", "Gabriel");
cout << "Enter message text line, enter . on new line to finish: " << endl;
while(getline(cin, text_input))
{
}
}
The getline method is giving me no instance of overloaded function. Also, from the same line, the text_input is showing identifier is undefined. I thought I declared in .h class already?
Thanks in advance.
Updated portion
Now all the error has been fixed:
vector <Message*> message_list;
Message* message1 = new Message("Saiful", "Gabriel");
cout << "Enter message text line, enter . on new line to finish: " << endl;
while(getline(cin, message1->get_text_input()))
{
if(message1->get_text_input() == ("."))
{
break;
}
else
{
message1->append(message1->get_text_input());
}
}
Inside the while loop, once "." is detected at the beginning of the new line, it supposingly will stop. However, no matter how many times I entered "." at the new line, it just keep prompting. Anybody know why?
To fix "text_input is showing identifier is undefined"
You need to change
while(getline(cin, text_input))
to
while(getline(cin, message1->text_input))
Possibly this will fix the first error.
Try changing your loop like this:
while(getline(cin,&message1->text_input))
{
}
If I remember correctly, getline function looks like this:
getline(isstream& stream, string& string)
It feels as if you are over complicating things. Just use a temporary variable in getline. If the input is a "." then break, otherwise append the line to the Message object. As a consequence, you should be able to remove the text_input member variable from your Message header file.
std::vector<Message*> message_list;
Message* message1 = new Message("Saiful", "Gabriel");
std::cout << "Enter message text line, enter . on new line to finish: " << std::endl;
std::string input = "";
while(getline(std::cin, input))
{
if(input == ".")
{
break;
}
else
{
message1->append(input);
}
}

While Loop contines forever to get end of input string

How do I run the while loop until the end of line or null character reached.
Here is my code
#include<iostream>
using namespace std;
main()
{
char input[20];
cout<<"Enter a line: ";
cin>>input;
while(input!='\0')
{
cout<<"This is a text";
}
system("pause");
}
If you want to read until either a newline or a NUL, read one character at a time inside the loop.
#include<iostream>
int main()
{
char input;
std::cout << "Enter a line: " << std::flush;
while(std::cin >> input && input != '\n' && input != 0) {
std::cout << "This is a test\n";
}
}
Notes:
main requires a return type
Never, ever, say "using namespace std;"
Don't forget to flush if you want cout to appear immediately.
Notice the compound test in the while condition:
First, did the read succeed?
Next, is it not '\n' (one of your conditions).
Next, is it not NUL (the other of your conditions).
The body of the loop will be executed once per input character -- is that what you wanted?
But, consider if you have correctly specified your requirement. It is an unusual requirement -- why would there be a NUL in a text file, and why would you want to process each character individually?
In idiomatic C++, you can read the input file in a line at a time using std::getline:
std::string myString;
while(std::getline(std::cin, myString)) {
// process myString
}
If you just want to read in a single line:
std::string myString;
if(std::getline(std::cin, myString)) {
// process myString
}
Finally, if you want to read a line, and ignore its contents:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
try something like:
i = 0;
while ((input[i] != '\0') && i < 20)
{
cout<<"This is a text";
i++;
}
Like this:
std::string line;
if (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
else
{
// error, e.g. EOF
}
If you want to read multiple lines, use a while loop instead:
while (std::getline(std::cin, line))
{
std::cout << "Thank you, you said, \"" << line << "\".\n";
}
The issue is that you're reading an entire chunk of text at once and then printing it until the input is '\0'. However, you're never actually updating this inside the loop. You can either use cin inside the loop to get the input, OR if you're trying to output each character, you can index the char array.