Issues with reading from a .txt file c++ - c++

I was seeking some help on an issue. I have to read certain "passwords" from a .txt file, like "abE13#" and do some simple error checking to make sure they fit certain requirements. But at the current moment, it's printing out the passwords (which is meant to be done), but it's ignoring the checking and gets stuck in a loop where new lines are being printed out. I'm sure it has to do something with while(ch!='\n') but I'm not all that sure what is needed there in place of that to check.
ch = inFile.get();
while(!inFile.eof())
{
while(ch != '\n')
{
cout << ch;
if(isalpha(ch))
{
charReq++;
if(isupper(ch))
uppercaseReq++;
else
lowercaseReq++;
}
else if(isdigit(ch))
{
charReq++;
digitReq++;
}
else if(isSpecial(ch))
{
charReq++;
specialCharReq++;
}
if(uppercaseReq < 1)
cout << "\n missing uppercase" << endl;
ch = inFile.get();
}
}
It's supposed to kind of follow this format,
Read a character from the password.txt file
while( there are characters in the file )
{
while( the character from the file is not a newline character )
{
Display the character from the file
Code a cascading decision statement to test for the various required characters
Increment a count of the number of characters in the password
Read another character from the password.txt file
}
Determine if the password was valid or not. If the password was invalid,
display the things that were wrong. If the password was valid, display that it
was valid.
Read another character from the file (this will get the character after the
newline character -- ie. the start of a new password or the end of file)
}
Display the total number of passwords, the number of valid passwords, and the
number of invalid passwords

It keeps prints because of this while(inFile). This is always true. Change it to an if statement just to check if file is open:
if ( inFile )
EDIT: It will stop at the first password because of this while(ch != '\n'). When he gets to the end of the first password ch will be '\n', while fails and stop reading. Change it to:
while( !inFile.eof() )

while( the character from the file is not a newline character )
You have converted this line of pseudocode into this line of c++ code:
while (ch != '\t')
'\t' is the tab character, not the newline character. This could definitely cause problems as to why you are never ending and instead just printing out new lines (Really EOF, but you don't see that).
'\n' is the newline character.
Give that a try.
EDIT:
Also, your only checking for an entire ifstream to be false. I don't quite know when that would happen, but I would recommend checking for the EOF flag. Your code should turn into something along the lines of this:
while( !inFile.eof() )
{
while(ch != '\n' && !inFile.eof() )
{
// ...
}
}

If you don't check for infile twice, you may end up in an infinite loop.
while(infile.good())
{
while (inFile.good() && ch != '\n')
{
...
}
if (ch == '\n')
{...}
else
{...}
}

Related

What does this do : while((c= getchar()) != '\n' && c != EOF);

while((c= getchar()) != '\n' && c != EOF);
I was facing a problem by using gets() to enter strings. I found on google that it was keeping the value of '\n' in the input buffer. I searched here and found the above code to solve my problem. However I don't quite get the hold of it. What does this do ?? Anybody please enlighten me.
An assignment in C++ will also yield the value being assigned. So c= getchar() is reading the next character from the file, and (c= getchar()) != '\n' is comparing that read character to the newline character. There's another test for the special EOF value, to make sure it doesn't keep trying to read once you reach the end of the file.
There's no statement between the while and the closing semicolon because nothing else needs to be done, you're throwing the input away.
The code introduces a while-loop. Its exit condition assigns the integer c the value that getchar() returns, and checks whether it is equal to the newline character ('\n') or EOF. If it is, the loop exits. If it isn't, the next character is extracted, and so on.
The code basically skips all characters until the next newline or EOF is reached. It is equivalent to:
for (;;)
{
c = getchar(); // c has been declared elsewhere
if (c == '\n' || c == EOF)
break;
}

How to check for '\n' character using getline() for c-strings

I am trying to increment the variable int lines everytime getline encounters a '\n' character in an input file. However, my variable isn't being incremented after a new line and I'm assuming maybe I'm not checking the buffer correctly that I'm loading the characters of the line into. Here is my code with much of it simplified:
int lines = 0;
while(input.getline(buffer, 100))
{
if(buffer[0] == '\n')
lines++;
}
File format(I want it to increment once it encounters the '\n' between the two lines of data):
20012 CSCI 109 04 90 1 25
-- ID days_constraint start_contraint
Thanks guys.
if(buffer[0] == '\n')
That will only work if the newline is the first character in the line, i.e. if it's a blank line. So you're only counting blank lines. It should have been:
if(buffer[strlen(buffer)] == '\n')
But as #DavidSchwartz points out, you don't need it at all.
Assume you used std::basic_istream::getline, you don't need the check whether '\n' in your buffer, because '\n' was used as the delimiter. So just increment every successful getline is OK.
int lines = 0;
while(input.getline(buffer, 100))
{
lines++;
}
//other handle exception logic
if (input.fail()
{
// lines number is not valid
}
if (input.bad())
{
//......
}
Assume file is valid and lines less than 100, or you should add exception handle logic.

Simple C++ not reading EOF

I'm having a hard time understanding why while (cin.get(Ch)) doesn't see the EOF. I read in a text file with 3 words, and when I debug my WordCount is at 3 (just what I hoped for). Then it goes back to the while loop and gets stuck. Ch then has no value. I thought that after the newline it would read the EOF and break out. I am not allowed to use <fstream>, I have to use redirection in DOS. Thank you so much.
#include <iostream>
using namespace std;
int main()
{
char Ch = ' ';
int WordCount = 0;
int LetterCount = 0;
cout << "(Reading file...)" << endl;
while (cin.get(Ch))
{
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
cout << "Number of words => " << WordCount << endl;
return 0;
}
while (cin >> Ch)
{ // we get in here if, and only if, the >> was successful
if ((Ch == '\n') || (Ch == ' '))
{
++WordCount;
LetterCount = 0;
}
else
++LetterCount;
}
That's the safe, and common, way to rewrite your code safely and with minimal changes.
(Your code is unusual, trying to scan all characters and count whitespace and newlines. I'll give a more general answer to a slightly different question - how to read in all the words.)
The safest way to check if a stream is finished if if(stream). Beware of if(stream.good()) - it doesn't always work as expected and will sometimes quit too early. The last >> into a char will not take us to EOF, but the last >> into an int or string will take us to EOF. This inconsistency can be confusing. Therefore, it is not correct to use good(), or any other test that tests EOF.
string word;
while(cin >> word) {
++word_count;
}
There is an important difference between if(cin) and if(cin.good()). The former is the operator bool conversion. Usually, in this context, you want to test:
"did the last extraction operation succeed or fail?"
This is not the same as:
"are we now at EOF?"
After the last word has been read by cin >> word, the string is at EOF. But the word is still valid and contains the last word.
TLDR: The eof bit is not important. The bad bit is. This tells us that the last extraction was a failure.
The Counting
The program counts newline and space characters as words. In your file contents "this if fun!" I see two spaces and no newline. This is consistent with the observed output indicating two words.
Have you tried looking at your file with a hex editor or something similar to be sure of the exact contents?
You could also change your program to count one more word if the last character read in the loop was a letter. This way you don't have to have newline terminated input files.
Loop Termination
I have no explanation for your loop termination issues. The while-condition looks fine to me. istream::get(char&) returns a stream reference. In a while-condition, depending on the C++ level your compiler implements, operator bool or operator void* will be applied to the reference to indicate if further reading is possible.
Idiom
The standard idiom for reading from a stream is
char c = 0;
while( cin >> c )
process(c);
I do not deviate from it without serious reason.
you input file is
this is fun!{EOF}
two spaces make WordCount increase to 2
and then EOF, exit loop! if you add a new line, you input file is
this is fun!\n{EOF}
I took your program loaded it in to visual studio 2013, changed cin to an fstream object that opened a file called stuff.txt which contains the exact characters "This is fun!/n/r" and the program worked. As previous answers have indicated, be careful because if there's not a /n at the end of the text the program will miss the last word. However, I wasn't able to replicate the application hanging in an infinite loop. The code as written looks correct to me.
cin.get(char) returns a reference to an istream object which then has it's operator bool() called which returns false when any of the error bits are set. There are some better ways to write this code to deal with other error conditions... but this code works for me.
In your case, the correct way to bail out of the loop is:
while (cin.good()) {
char Ch = cin.get();
if (cin.good()) {
// do something with Ch
}
}
That said, there are probably better ways to do what you're trying to do.

what does -1 represent in ASCII?

I'm working on an automatic summarization system in my C++ class and have a question regarding one of the ASCII comparisons I'm doing. Here's the code:
char ch;
string sentence;
pair<char, char> sentenceCheck;
int counter = 0;
while (!ifs2.eof())
{
ch = ifs2.get();
ch = tolower(ch);
if (ch == 13)
ch = ifs2.get();
if (ch != 10 && ch != '?' && ch != '!' && ch != '.')
sentence += ch;
sentenceCheck.first = sentenceCheck.second;
sentenceCheck.second = ch;
cout << sentenceCheck.first << "-" << (int)sentenceCheck.first << " ---- " << sentenceCheck.second << "-" << (int)sentenceCheck.second << endl;
if(sentenceCheck.second == ' ' || sentenceCheck.second == 10 || sentenceCheck.second == -1)
{
if(sentenceCheck.first == '?' || sentenceCheck.first == '!' || sentenceCheck.first == '.')
{
istringstream s(sentence);
while(s >> wordInSentence)
{
sentenceWordMap.insert(pair<string, int>(wordInSentence, 0));
}
//sentenceList.push_back(pair<string, int>(sentence, 0));
sentence.clear();
}
}
}
What is being done here (with the two if statements) is checking whether a new sentence has begun in the text that is to be analyzed and dealt with later. The conditionals work but only because we discovered that we have to check for that -1 as well. Any ideas what that represents?
-1 doesn't represent anything in ASCII. All ASCII codes are in the range [0, 127]. It's not even guaranteed by C++ that -1 is a valid value for a char.
The problem is that you're not checking the return value from ifs2.get(), which returns an int (not a char!) that may be -1 on end of file. The proper way to check for this is
int ch = ifs2.get();
if (!ifs2)
// break the loop
because the EOF value is not guaranteed to be -1 (it's actually std::char_traits<char>::eof()).
(Btw., you shouldn't write ASCII codes as magic numbers; use \n for linefeed, \r for carriage return.)
The while is incorrectly structured: you need to check eof() immediately after get():
for (;;)
{
ch = ifs2.get();
if (ifs2.eof()) break;
ch = tolower(ch);
if (ch == 13)
{
ch = ifs2.get();
if (ifs2.eof()) break;
}
...
}
The -1 is probably the EOF indicator.
Note (as has already been stated) get() returns an int, not a char.
As an ASCII character -1 doesn't represent anything (which is to say -1 is not a valid ASCII value). As the return value from get() it means that the read operation failed - most likely due to the end of file being reached.
Note that the eof() function doesn't return true if the next call to get will fail because of the end of file being reached - it returns true if the previous call to get failed because of the end of file being reached.
It's not ASCII, it's an error returned by istream::get
ch = ifs2.get();
It's probably EOF, i.e. you've run out of input.
The fact that checking for -1 works is an accident, and has nothing to
do with ASCII values (which only use 0 to 127). Your code will fail
if either plain char is unsigned (compile with /J with VC++, I think),
or EOF isn't -1 (rare, but all that's guaranteed is that it is
negative). You're code will also fail if the input happens to be
Latin-1, and it contains a 'ÿ'.
The basic problem in your code is that you're not checking for end of
file correctly. Putting the test at the top of the loop doesn't work;
you need to test for failure (not eof()) after input, before using
the value read. There are several ways of doing this; in your case, the
simplest is probably to use:
if ( !ifs2.get(ch) ) {
// Input failed...
}
Alternatively, you can make ch an int, and do:
ch = ifs2.get();
if ( ch == EOF ) {
// Input failed...
}
This has the advantage that the following call to tolower is no longer
undefined behavior (tolower takes an int, which must be in the range
[0...UCHAR_MAX] or EOF—if plain char is signed, you aren't
guaranteeing this). On the other hand, it doesn't allow chaining, i.e.
you can't write the equivalent of:
while ( ifs2.get( sentenceCheck.first )
&& ifs2.get( sentenceCheck.second ) ) {
// ...
}
(which could be useful in some cases).
FWIW: the technique you're using is something called a sliding window
into a stream, and it's worth pushing it off into a separate class to
handle the logic of keeping the window filled and up to date.
Alternatively, a simple state machine could be used for your problem.
And I'd definitely avoid using magic constants: if you want to check for
a carriage return, compare with '\r'. Similarly, newline is '\n',
and in the outer if, it looks like you want to check for whitespace
(isspace( static_cast<unsigned char>( sentenceCheck.second ) )),
rather than comparing for the values.
I might also add that your code fails to correctly handle sentences that
end with a quote, like This is the "text in your input."; it also
fails for abbreviations like Mr. Jones is here.. But those problems
may be beyond the scope of your assignment. (The abbreviations one is
probably not fully solvable: sometimes "etc." is the end of a
sentence, and sometimes it's not.)

Reading from ifstream won't read whitespace

I'm implementing a custom lexer in C++ and when attempting to read in whitespace, the ifstream won't read it out. I'm reading character by character using >>, and all the whitespace is gone. Is there any way to make the ifstream keep all the whitespace and read it out to me? I know that when reading whole strings, the read will stop at whitespace, but I was hoping that by reading character by character, I would avoid this behaviour.
Attempted: .get(), recommended by many answers, but it has the same effect as std::noskipws, that is, I get all the spaces now, but not the new-line character that I need to lex some constructs.
Here's the offending code (extended comments truncated)
while(input >> current) {
always_next_struct val = always_next_struct(next);
if (current == L' ' || current == L'\n' || current == L'\t' || current == L'\r') {
continue;
}
if (current == L'/') {
input >> current;
if (current == L'/') {
// explicitly empty while loop
while(input.get(current) && current != L'\n');
continue;
}
I'm breaking on the while line and looking at every value of current as it comes in, and \r or \n are definitely not among them- the input just skips to the next line in the input file.
There is a manipulator to disable the whitespace skipping behavior:
stream >> std::noskipws;
The operator>> eats whitespace (space, tab, newline). Use yourstream.get() to read each character.
Edit:
Beware: Platforms (Windows, Un*x, Mac) differ in coding of newline. It can be '\n', '\r' or both. It also depends on how you open the file stream (text or binary).
Edit (analyzing code):
After
while(input.get(current) && current != L'\n');
continue;
there will be an \n in current, if not end of file is reached. After that you continue with the outmost while loop. There the first character on the next line is read into current. Is that not what you wanted?
I tried to reproduce your problem (using char and cin instead of wchar_t and wifstream):
//: get.cpp : compile, then run: get < get.cpp
#include <iostream>
int main()
{
char c;
while (std::cin.get(c))
{
if (c == '/')
{
char last = c;
if (std::cin.get(c) && c == '/')
{
// std::cout << "Read to EOL\n";
while(std::cin.get(c) && c != '\n'); // this comment will be skipped
// std::cout << "go to next line\n";
std::cin.putback(c);
continue;
}
else { std::cin.putback(c); c = last; }
}
std::cout << c;
}
return 0;
}
This program, applied to itself, eliminates all C++ line comments in its output. The inner while loop doesn't eat up all text to the end of file. Please note the putback(c) statement. Without that the newline would not appear.
If it doesn't work the same for wifstream, it would be very strange except for one reason: when the opened text file is not saved as 16bit char and the \n char ends up in the wrong byte...
You could open the stream in binary mode:
std::wifstream stream(filename, std::ios::binary);
You'll lose any formatting operations provided my the stream if you do this.
The other option is to read the entire stream into a string and then process the string:
std::wostringstream ss;
ss << filestream.rdbuf();
OF course, getting the string from the ostringstream rquires an additional copy of the string, so you could consider changing this at some point to use a custom stream if you feel adventurous.
EDIT: someone else mention istreambuf_iterator, which is probably a better way of doing it than reading the whole stream into a string.
Wrap the stream (or its buffer, specifically) in a std::streambuf_iterator? That should ignore all formatting, and also give you a nice iterator interface.
Alternatively, a much more efficient, and fool-proof, approach might to just use the Win32 API (or Boost) to memory-map the file. Then you can traverse it using plain pointers, and you're guaranteed that nothing will be skipped or converted by the runtime.
You could just Wrap the stream in a std::streambuf_iterator to get data with all whitespaces and newlines like this .
/*Open the stream in default mode.*/
std::ifstream myfile("myfile.txt");
if(myfile.good()) {
/*Read data using streambuffer iterators.*/
vector<char> buf((std::istreambuf_iterator<char>(myfile)), (std::istreambuf_iterator<char>()));
/*str_buf holds all the data including whitespaces and newline .*/
string str_buf(buf.begin(),buf.end());
myfile.close();
}
By default, this skipws flag is already set on the ifstream object, so we must disable it. The ifstream object has these default flags because of std::basic_ios::init, called on every new ios_base object (more details). Any of the following would work:
in_stream.unsetf(std::ios_base::skipws);
in_stream >> std::noskipws; // Using the extraction operator, same as below
std::noskipws(in_stream); // Explicitly calling noskipws instead of using operator>>
Other flags are listed on cpp reference.
The stream extractors behave the same and skip whitespace.
If you want to read every byte, you can use the unformatted input functions, like stream.get(c).
Why not simply use getline ?
You will get all the whitespaces, and while you won't get the end of lines characters, you will still know where they lie :)
Just Use getline.
while (getline(input,current))
{
cout<<current<<"\n";
}
I ended up just cracking open the Windows API and using it to read the whole file into a buffer first, and then reading that buffer character by character. Thanks guys.