I'm doing an exercise in C++ Primer and basically I am using a switch statement to count the number of vowels in a text that I input.
I input the text using a while loop.
while(cin >> ch)
and proceed with the cases, a, e, i, o, u, incrementing an integer variable for the respective cases. Now the next part of the question says also count the spaces, tabs and newlines.
I tried doing
case ' ':
and so forth using '\t' and '\n'. But it seems like it doesn't compute these cases. I also tried just using a default and using an if else statement
default:
if(ch == ' ')
++space;
etc. But this doesn't proceed either. I also tried putting in the integer values of ' ', '\t', '\n'. What am I doing wrong here? Also, I know that if I use isspace() I can count the combined total but I need to compute each one individually. I'm not sure why the equality test won't do the job.
By default, formatted input from streams skips leading whitespace. You need to either disable skipping of leading whitespaces or use one of the functions which won't skip spaces:
std::cin >> std::noskipws; // disables skipping of leading whitespace
char c;
while (std::cin.get(c)) { // doesn't skip whitespace anyway
...
}
As said by Dietmar, white spaces are skipped by default. You could use cin.getline() to provide your own string delimiter instead of white space characters. I would say this is a generally easier way of reading input compared to using cin.get().
Related
I have an input text file. The first line has two int numbers a and b, and the second line is a string. I want to use formatted input to do file >> a >> b, and then unformatted input to get the characters of the string one by one. In between the two steps, I need to skip over the '\n' character at the end of the first line. I used
while(file.get()<=' ' && !file.eof()); // skip all unprintable chars
if(!file.eof()) file.unget(); // keep the eof sign once triggered
to make the input format more flexible. The user can now separate the numbers a and b from the string using an arbitrary number of empty lines '\n', tab keys '\t', and/or space keys ' ' -- the same freedom he has to separate the numbers a and b. There's even no problem reading in Linux a text file copied from Windows when every end of line now becomes "\r\n".
Is there an ifstream function that does the same thing (skip all chars <=' ' until the next printable char or EOF is reached)? The ignore function does not seem to do that.
Yes, there is: std::ws manipulator. It skips whitespace characters until a non-whitespace is found or end of stream is reached.. It is similar to use of whitespace character in scanf format string.
In fact, it is used by formatted input before actually starting to parse characters.
You can use it like that:
int x;
std::string str;
std::cin >> x >> std::ws;
std::getline(std::cin, str);
//...
//std::vector<int> vec;
for(auto& e: vec) {
std::cin >> e;
}
std::getline(std::cin >> std::ws, str);
I tried to compare std::cin and scanf, I expected them to have same behavior, but actually not:
#include<iostream>
using namespace std;
int main()
{
int i;
cin>>i;
return 0;
}
This receives an input from user, no problem.
But
#include<stdio.h>
int main()
{
int i;
scanf("%d\n",&i);
return 0;
}
I input a integer, program doesn't terminate even if I press "enter" multiple times, unless I enter another integer number.
Note there's an "\n" in scanf's format string.
So I tried to add one statement
printf("%d\n", i);
Well it prints out the 1st number I just input. This is correct but weird, why after scanf, the program requires me to enter any character rather then \n, to exit the program?
I tried both VC and GCC, same problem. What is that \n indicating?
scanf("%d\n",&i);
Let's read the manpage of scanf :
Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters -- see isspace). A single whitespace in the format string validates any quantity of whitespace characters extracted from the stream (including none).
What it means is scanf will search for a integer followed by an optionnal whitespace. that's why he's waiting for you to use two times enter. If you used "%d\n\n", it'll have to be three times. And so on.
If you want only an interger, use scanf("%d",&i);
scanf("%d\n",&i); is equivalent to std::cin >> i >> std::ws;.
If you want the same behaviour for scanf, remove \n: scanf("%d",&i);
This is caused by the fact that any whitespace character in scanf means "skip input until non-whitespace is found"
For a small portion of my project, I'm supposed to extract data from a text file using cin which my program will know where to cin from based on command line arguments. My issue is how to extract the four pieces of data and ignore the commas. For example, the .txt file will look like the following
(1,2,3,.)
(2,1,3,#)
(3,1,0,.)
In which case I need to extract the 1, the 2, the 3, and the . for the first line. Then move to the second line. When a blank newline is reached than I can exit the getline() scenario through a while loop.
I know I need to use getline() and I was able to extract the data by using the .at() function of the string generated by getline(). I became confused however when a coordinate such as the 1, the 2, or the 3, could be double digits. When this happened, my previous algorithm didn't work so I feel I'm overthinking things and there should be a simpler way to parse this data.
Thanks!
You can just use the >> operator to a dummy 'char' variable to read in the separators. This assumes you don't care about the 4th token and that it's always a single character:
char ch;
while (ss >> ch)
{
int a,b,c;
ss >> a >> ch >> b >> ch >> c >> ch >> ch >> ch;
}
A simple approach is to use sscanf, pass the string you read from cin to it as the first argument
sscanf(s, "(%d,%d,%d,%c)", &a, &b, &c))
If you want to parse the string from scratch, just focus the pattern.
In this case, the pattern is
'(', number, ',', number, ',', number, ',', char, ')'
So you can locate the three commas, then simply extract three numbers from between them.
A more complicated method is regex.
But C++ doesn't have native support for that (the Boost library does)
I have a doubt regarding using getchar() to read a character input from the user.
char char1, char2;
char1 = getchar();
char2 = getchar();
I need to get 2 chars as inputs from the user. In this case, if the user enters the character 'A' followed by a newline, and then the character 'B', what will be stored in char2 - will it be the newline character or the character 'B'?
I tried it on CodeBlocks on Windows, and char2 actually stores the newline character, but I intended it to store the character 'B'.
I just want to know what the expected behavior is, and whether it is compiler-dependent? If so, what differences hold between turbo C and mingW?
Yes, you have to consume newlines after each input:
char1 = getchar();
getchar(); // To consume `\n`
char2 = getchar();
getchar(); // To consume `\n`
This is not compiler-dependent. This is true for all platforms as there'll be carriage return at the end of each input line (Although the actual line feed may vary across platforms).
I just want to know what the expected behavior is, and whether it depends on the compiler-dependent?
That's the expected behavior and not compiler-dependent.
You can use scanf to read A followed by newline, then B followed by newline. If you want to stick to getchar(), then simply give the input as AB.
You can prevent reading newlines by explicitly testing for it.
Instead of simply using
getchar():
you can use something like this
while((char1 = getchar()) == '\n');
If you're on windows you might want to test for '\r' too. So the code changes a little.
while((char1 = getchar()) == '\n' || char1 == '\r');
add statement fflush(stdin); in between statements.
look this one
ch1=getchar();
fflush(stdin);
ch2=getchar();
I have a text file with lines of text that have a string another string followed by up to 4 integers,
ex:
clear "clear water.png" 5 7
wet "wet water.png" 9 5 33 17
soft "soft rain falling.png"
The only way I see it is:
read until space is found
set string to wet
read until double quote
read until second double quote
set second string to wet water.png
while not end of line
read until space
put string through string stream
push resulting integer into vector of int
Is there a better way to do this?
Thanks
This is the sort of task for which scanf and company truly shine.
char first_string[33], second_string[129];
sscanf(input_string,
"%32s%*[^\"]%*c%128[^\"]%*c %d %d %d %d",
first_string,
second_string,
&first_int,
&second_int,
&third_int,
&fourth_int);
You probably want to do that in an if statement so you can test the return value, to tell you how many of those fields converted (e.g., so you know how many integers you read at the end).
Edit: perhaps some explanation would be helpful. Let's dissect that:
%32s reads a string to the first white-space (or 32 characters, whichever comes first).
%*[^\"] ignores input up to the first ".
%*c ignores one more byte of input (the quote itself)
%128[^\"] reads the string in the quote (i.e., up to the next quote character).
%*c Ignores the closing quote
%d Reads an int (which we've done four times).
The space before each %d is really unnecessary -- it'll skip whitespace, but without the space, %d will skip leading whitespace anyway. I've included them purely to make it a little more readable.
Ugly, with no error-checking, but no dependencies on any non-standard libraries:
string s;
while(getline(fin, s))
{
string word, quoted_string;
vector<int> vec;
istringstream line(s);
line >> word;
line.ignore(numeric_limits<streamsize>::max(), '"');
getline(line, quoted_string, '"');
int n;
while(line >> n) vec.push_back(n);
// do something with word, quoted_string and vec...
}
Depending on the restrictions of the input strings you could trying splitting on double-quote then splitting on space.
Yes
Use getline to read one line at a time. Parse the lines using a regular expression library.