When using stdio.h
, I can easily read certain kinds of formatted input like this:
FILE* fin = fopen(...);
fscanf(fin, "x = %d, y = %d", &x, &y);
The great thing about this is that I don't really have to worry about how many spaces there are between the character 'x' and the following '=', and other minor details.
In C++ it appears to me as though,
ifstream fin(...);
string s;
fin >> s;
may result in s
being "x"
or "x="
, or even "x=12"
depending on the spacing of the input.
Is there a convenient way to get behavior similar to scanf
/fscanf
using iostream
/fstream
?
The C language comes with standard functions printf() and scanf() so that a programmer can perform formatted output and input in a program. The formatted functions basically present or accept the available data (input) in a specific format.
The fscanf() function reads data from the current position of the specified stream into the locations that are given by the entries in argument-list, if any. Each entry in argument-list must be a pointer to a variable with a type that corresponds to a type specifier in format-string.
1.1 Streams C/C++ IO are based on streams, which are sequence of bytes flowing in and out of the programs (just like water and oil flowing through a pipe). In input operations, data bytes flow from an input source (such as keyboard, file, network or another program) into the program.
This is actually surprisingly easy, given a prerequisite. I have these three functions that I stick in a header somewhere. These allow you to stream in character literals, and string literals. I've never quite understood why these aren't standard.
#include <iostream>
//These are handy bits that go in a header somewhere
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e(&sliteral)[N]) {
e buffer[N-1] = {}; //get buffer
in >> buffer[0]; //skips whitespace
if (N>2)
in.read(buffer+1, N-2); //read the rest
if (strncmp(buffer, sliteral, N-1)) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& cliteral) {
e buffer(0); //get buffer
in >> buffer; //read data
if (buffer != cliteral) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
//redirect mutable char arrays to their normal function
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, e(&carray)[N]) {
return std::operator>>(in, carray);
}
Given those, the rest is easy:
in>>'x'>>'='>>data.first>>','>>'y'>>'='>>data.second;
Proof here
For more complex situations, you probably want to use std::regex
or boost::regex
, or maybe a real lexer/parser.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With