I am reading in a text file and have found that it will not print the blank characters between the words. I want to read each character a character at a time and then print the character to the output window. The read will read the file but does not show the blank spaces and I have not been able to find out why the blank spaces are being skipped.
Question: Why is my read not reading the blank characters in my test file?
When i find a blank character I want to print the word Blank Space.
Code:
#include "stdafx.h"
#include "iostream"
#include<iostream>
#include<fstream>
void readTestFile()
{
char ch;
std::fstream fin("C:/Users/itpr13266/Desktop/myTest.txt", std::fstream::in);
while (fin >> ch) {
std::cout << "Letter: " << ch << std::endl;
if (ch == ' ') <-- should catch a blank spaces
{
std::cout << "Blank Space" << std::endl;
}
else <-- Just write the letter
{
std::cout << ch << std::endl;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
readTestFile();
getchar();
return 0;
}
Test File:
This is testing for fprintf...
This is testing for fputs...
Output
Letter: T
T
Letter: h
h
...etc...
The standard input function istream::operator>>() skips all leading whitespace before performing input. If you need to obtain spaces, there are a couple options you can use:
std::noskipws
By setting the std::ios_base::noskipws flag, the stream will not discard leading whitespace and ch will be given the value of each consecutive character. Note that this succeeds only with the overload that takes a char (ch will be given the value of the space). For any other data type this will not work:
while (fin >> std::noskipws >> ch)
{
// ...
}
std::istream::get()
get() is an UnformattedInputFunction function, and thus will not parse the input beforehand.
while (fin.get(ch))
{
// ...
}
std::istreambuf_iterator<>
You can also use iterators to work directly with the buffer. std::istreambuf_iterator<> also doesn't parse the input:
std::copy(std::istreambuf_iterator<char>{fin},
std::istreambuf_iterator<char>{},
std::ostreambuf_iterator<char>{std::cout},
You are performing formatted input, use unformatted input
std::fstream::traits_type::int_type ch;
while((ch = fin.get()) != std::fstream::traits_type::eof()) {
// ...
}
By default, operator>> on streams skips any leading whitespace before parsing the value. This is, for example, what allows you to read the input 30 60 95 with int i,j,k; fin >> i >> j >> k; (otherwise reading j would fail because after the 30, there follows a space, not an integer).
You now have two options if you want to read the spaces as well:
(preferred): Use the member function get() for unformatted reading of a character.
Instruct the stream not to eat whitespace before reading: fin >> std::noskipws >> ch.
Read more about the different iostream methods. In particular, you are using istream's operator>>. Take careful note of how it is designed to work; it uses whitespace as a delimiter and does not store the whitespace.
If you want to read every char from your stream (e.g. a file stream), you should not be using >>, but rather consider using istream::get().
// stream is an istream, such as cin or ifstream
char ch;
while (ch = stream.get()) { }
This worked for me. I set it in a function so you can copy paste. It detects the space, and also the change in line. I tried it with ASCII art and it worked fine.
void print2()
{
char ch;
std::fstream myStream("GameOver.txt", std::fstream::in);
while (myStream.get(ch))
{
std::cout << ch;
}
}
Related
i want to proccess user input which is a line of string. with string library it's just easy as cin >> mystring; , but for performance reasons, i'd like to process a character at a time without saving previous characters or using any kind of arrays. so i wrote this code:
char myc;
while(cin >> myc){
dosomething(myc);
}
but after writing a line of string as input and hitting enter, it processes input characters and still waits for more input characters to come.
i also used cin.eof() and while(myc) but none of them worked.
You have to check for line break but you can't do it with std::istream::operator>> because it is formatted read and skips newline. Use
char myc;
while ((myc = cin.get()) != '\n')
dosomething(myc);
}
To read a stream character-wise use std::basic_istream<CharT,Traits>::get function:
for(char c; std::cin.get(c);) {
std::cout << c;
}
So I was taking input some integers and then taking input some sentences.
This code works fine:
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
cin>>ws;
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makesNo sense
No sense
However, when I try to omit the cin>>ws inside the forloop, it doesn't work properly, eg this code segment,
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makes
..and terminates there instead of taking all three inputs.
Why is that? cin>>ws extracts all whitespace from the input but isn't getline() doing that too? So why does it not work properly when I omit cin>>ws in the forloop?
std::getline() extract characters until it extracted the first delimiter character (by default '\n'). The delimiter is not stored in the result but it is extracted. It does not extract whitespace in general or multiple delimiter characters.
As an aside: always check whether input works after trying to read a value.
In the example printed, the issue is is that after formatted input, i.e., using the >> operator, whitespaces are not extracted. That is, the first calls to std::getline() extracts the empty string terminated by the initial newline. It generally is necessary to extract trailing whitespace when switching between formatted and unformatted I/O. That is, You'd want code like
if (cin>>n>>b>>c >> std::ws) {
for(i=0;i<n;i++){
if (getline(cin,s,'\n')) {
cout << "i=" << i << ":'" << s << "'\n";
}
}
}
I can't recommend input operations without adding check for success. The output is changed to make it more easily visible what is going on: try the code with/without this particular std::endl to see what is happening.
When you use cin >> it doesn't remove any whitespace after the input. This means the newline that terminated the first 3 inputs is still in the buffer, waiting to be read by the first getline. Since there's nothing before the newline, the first getline delivered an empty string. Your output should have included a newline so you could have seen the empty line, then it would have made sense.
Originally the code you posted showed a cin >> ws just before the for loop which would have eliminated this problem.
The default delimiter for getline() is '\n', so there is no need to include that in the getline call, though, it should not change the functionality.
See for example Same as getline(input, str, input.widen('\n')), that is, the default delimiter is the endline character.
The change in formatting from the integer input to the getline() input leaves some whitespace (endl) after the integer as explained by #DietmarKühl.
You can change the getline() call to eliminate the delimiter to
getline(cin,s);
which will cause getline() to use '\n' as the default delimiter.
I have modified the 'n' variable to count and removed the other integers to make the code a little simpler to read:
#include <iostream>
int main()
{
int i; // index
int count; // number of strings to accept
std::string str;
std::cout << "Input the number of strings you would like me to process: " << std::endl;
std::cin >> count;
if (std::cin >> count >> std::ws) {
for (i = 0; i < count; i++) {
if (getline(std::cin, str)) {
std::cout << "i=" << i << ":'" << str << "'\n";
}
}
}
}
Cin doesn't extract all white spaces, it just gets the first word until the first white space. It is like having a getline with a space delimiter(not quite but close to).
Getline takes the whole line and has the default '\n' delimiter like mentioned above.
Ex:
string a = "Stack Overflow is awesome";
can give you Stack and getline will give you everything at that line
I have this code
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char **argv) {
ifstream in;
in.open(*(argv+1));
char c;
while (true) {
if (in.eof())
break;
c = in.get();
cout << c;
}
in.close();
return 0;
}
I read the file which is passed via the command line as the first argument.
While reading the file, I get the char '?' as the last one. Why?
If I remove this line
in.open(*(argv+1));
I will get only the char '?'.
In the while loop you end up reading eof:
c = in.get(); // reads eof
cout << c;
This is not the best way to read a text file, use
while(in >> c){ // process c here }
or
while(in >> std::noskipws >> c) { // process c here }
if you want the white spaces (like \n) included.
If your file is in binary, then it doesn't make too much sense to display it, but if you want, then use get() but test if(!in) break; before further processing
c = in.get();
if (!in) // test the stream
break;
cout << c; // then process
If you just want to display the file, the easiest way is to use the stream buffer directly, like
std::cout << in.rdbuf(); // display the whole file at once
Related: Why is iostream::eof inside a loop condition considered wrong?
The istream::get() method returns an untranslated value from the input stream.
If the value is not printable, your console may translate the character to '?'.
A better method is to print the value of the character along with the character:
cout << "\'" << c << "\', 0x" << hex << ((unsigned int) c) << endl;
This will allow you to see unprintable characters.
I have been working on this for a while and can't fix it. I am very new to C++. So far I can get 10 things into my array but the output is not legible, it's just a bunch of numbers. I have read other posts with similar code but for some reason mine isn't working.
The input text file is 10 lines of fake data like this:
56790 "Comedy" 2012 "Simpsons" 18.99 1
56791 "Horror" 2003 "The Ring" 11.99 7
My code is here:
(My output is below my code)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct DVD {
int barcode;
string type;
int releaseDate;
string name;
float purchaseprice;
int rentaltime;
void printsize();
};
int main () {
ifstream in("textfile.exe");
DVD c[10];
int i;
for (int i=0; i < 10; i++){
in >> c[i].barcode >> c[i].type >> c[i].releaseDate >>
c[i].name >> c[i].purchaseprice >> c[i].rentaltime;
}
for (int i=0;i< 10;i++) {
cout << c[i].barcode<<" ";
cout << c[i].type<<" ";
cout << c[i].releaseDate<<" ";
cout << c[i].name << " ";
cout << c[i].purchaseprice << " ";
cout << c[i].rentaltime << "\n";
}
return 0;
}
My output looks similar to garbage, but there are 10 lines of it like my array:
-876919876 -2144609536 -2.45e7 2046
A comment on what to study to modify my code would be appreciated.
As suggested by cmbasnett, ifstream in("textfile.exe") reads in an executable file. If you with for the program to read in a text file, changing it to ifstream in("textfile.txt") should work.
You always need to check that your input is actually correct. Since it may fail prior to reading 10 lines, you should probably also keep a count of how many entries you could successfully read:
int i(0);
for (; i < 10
&& in >> c[i].barcode >> c[i].type >> c[i].releaseDate
>> c[i].name >> c[i].purchaseprice >> c[i].rentaltime; ++i) {
// ???
}
You actual problem reading the second line is that your strings are quoted but the approach used for formatted reading of strings doesn't care about quotes. Instead, strings are terminated by a space character: the formatted input for strings will skip leading whitespace and then read as many characters until another whitespace is found. On your second line, it will read "The and then stop. The attempt to read the purchaseprice will fail because Ring isn't a value numeric value.
To deal with that problem you might want to make the name quotedstring and define an input and output operators for it, e.g.:
struct quoted_string { std::string value; };
std::istream& operator>> (std::istream& in, quoted_string& string) {
std::istream::sentry cerberos(in); // skips leading whitespace, etc.
if (in && in.peek() == '"') {
std::getline(in.ignore(), string.value, '"');
}
else {
in.setstate(std::ios_base::failbit);
}
return in;
}
std::ostream& operator<< (std::ostream& out, quoted_string const& string) {
return out << '"' << string.value << '"';
}
(note that the code isn't test but I'm relatively confident that it might work).
Just to briefly explain how the input operator works:
The sentry is used to prepare the input operation:
It flushes the tie()d std::ostream (if any; normally there is none except for std::cin).
It skips leading whitespace (if any).
It checks if the stream is still not in failure mode (i.e., neither std::ios_base::failbit nor `std::ios_base::badbit are set).
To see if the input starts with a quote, in.peek() is used: this function returns an int indicating either that the operation failed (i.e., it returns std::char_traits<char>::eof()) or the next character in the stream. The code just checks if it returns " as it is a failure if the stream returns an error or any other character is present.
If there is a quote, the quote is skipped using file.ignore() which by default just ignores one character (it can ignore more characters and have a character specified when to stop).
After skipping the leading quote, std::getline() is used to read from file into string.value until another quote is found. The last parameter is defaulted to '\n' but for reading quoted string using a '"' is the correct value to use. The terminating character is, conveniently, not stored.
I am reading a std::istream and I need to verify without extracting characters that:
The stream is not "empty", i.e. that trying to read a char will not result in an fail state (solved by using peek() member function and checking fail state, then setting back to original state)
That among the characters left there is at least one which is not a space, a tab or a newline char.
The reason for this is, is that I am reading text files containing say one int per line, and sometimes there may be extra spaces / new-lines at the end of the file and this causes issues when I try get back the data from the file to a vector of int.
A peek(int n) would probably do what I need but I am stuck with its implementation.
I know I could just read istream like:
while (myInt << myIstream) {…} //Will fail when I am at the end
but the same check would fail for a number of different conditions (say I have something which is not an int on some line) and being able to differentiate between the two reading errors (unexpected thing, nothing left) would help me to write more robust code, as I could write:
while (something_left(myIstream)) {
myInt << myIstream;
if (myStream.fail()) {…} //Horrible things happened
}
Thank you!
There is a function called ws which eats whitespace. Perhaps you could call that after each read. If that hits eof, then you know you've got a normal termination. If it doesn't and the next read doesn't produce a valid int, then you know you've got garbage in your file. Maybe something like:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream infile("test.dat");
while (infile)
{
int i;
infile >> i;
if (!infile.fail())
std::cout << i << '\n';
else
std::cout << "garbage\n";
ws(infile);
}
}
this is what I did to skip whitespace/detect EOF before the actual input:
char c;
if (!(cin >> c)) //skip whitespace
return false; // EOF or other error
cin.unget();
This is independent of what data you are going to read.
This code relies on the skipws manipulator being set by default for standard streams, but it can be set manually cin >> skipw >> c;
And simple
for(;;){
if(!(myIstream >> myInt)){
if(myIstream.eof()) {
//end of file
}else{
//not an integer
}
}
// Do something with myInt
}
does not work? Why you need to know if there are numbers left?
Edit Changed to Ben's proposition.
The usual way to handle this situation is not to avoid reading from the stream, but to put back characters, which have been read, if needed:
int get_int(std::istream& in)
{
int n = 0;
while(true) {
if (in >> n)
return n;
clean_input(in);
}
}
void clean_input(std::istream& in)
{
if (in.fail()) {
in.clear();
// throw away (skip) pending characters in input
// which are non-digits
char ch;
while (in >> ch) {
if (isdigit(ch)) {
// stuff digit back into the stream
in.unget();
return;
}
}
}
error("No input"); // eof or bad
}