How I can read in those elements and store them into two different arrays., i.e. : the number in <?> and the word in [?] to be separately read in and stored.
<98>
Avs [adadada]
<45>
[adafaf] BBBHADA
asdadqd aada [Mammoth]
<-1> // ends the read
The rest of the info in the file is useless which do not require to be stored.
Edit:
Following the advice of one of the answers, here is my first attempt:
#include <iostream>
#include <sstream>
#include <fstream>
#include <string.h>
using namespace std;
int main(int argc, char* argv[])
{
if(argc != 3)
cout<< "Error! Not enough file!"<<endl;
int** page = new int*[];
char** words = new char*[];
}
//---------------------------------------------------------
void readInput(int** page1, char** name1){
istream is;
char par1, par2;
int usefulVal;
is >> par1 >> usefulVal >> par2;
// check if any input
if(!is) return is;
// check for valid input format
if (par1 != '<' || par2 != '>'){
// set failbit to indicate invalid input format
is.clear(ios_base::failbit);
// assign input values to second argument
page1(usefulVal);
char par_1, par_2;
string string_value;
is >> par1 >> string_value >> par2;
if(!is) return is;
if (par_1 != '[' || par_2 != ']')
{
is.clear(ios_base::failbit);
return is;
}
name1(string_value);
return is;
}
Question:
1. Is there a way to read and store the above elements separately?
2. What am I doing wrong?
P.S.: I'm just trying out some C++. Hope someone can shed some light on it, thanks!
To specify your format and read only specific elements you could overload the operator >>. For example, the first format: < int_value >, could be implemented with:
istream& operator>>(istream& is, class_name& array_name){
char par2, par2;
int int_value;
is >> par1 >> int_value >> par2;
// check if any input
if(!is) return is;
// check for valid input format
if (par1 != '<' || par2 != '>'){
// set failbit to indicate invalid input format
is.clear(ios_base::failbit);
return is;
}
// assign input values to second argument
array_name(int_value);
// chain for consecutive use
return is;
}
and the second format: [ string_value ] with:
istream& operator>>(istream& is, class_name& separate_array_name){
char par2, par2;
string string_value;
is >> par1 >> int_value >> par2;
if(!is) return is;
if (par1 != '[' || par2 != ']'){
is.clear(ios_base::failbit);
return is;
}
separate_array_name(string_value);
return is;
}
Note:
The second parameter in both examples: class_name& array_name and class_name& separate_array_name are not real types and are left for you to decide/ implement.
Edit:
The function you've defined is not used in your main().
The function needs to be either defined before the main() or forward declared.
Limit the excessive use of pointers and dynamically allocated memory, as it needs to be taken care of (freed) at the end.
Look up how to use istream: file name, modes, etc.
Prefer simple functions, i.e. doing one single process. It is much more easier to implement and detect errors.
Related
int a, b, c, d;
There are 4 variables.
I want user to input 4 values, and each value is separated by comma(,)
Just like this:
stdin:
1,2,3,4
The following code works in C
scanf("%d,%d,%d,%d", &a, &b, &c, &d);
But how should I code in C++?
I’m kind of surprised at the incorrect commentary here[1].
There are two basic routes you can take:
handle the separator with a manipulator-style object, or
imbue the stream with a specialized facet that requires whitespace to include a comma.
I will focus on the first; it is typically a bad idea to imbue shared streams with weird behaviors even temporarily (“shared” in the sense that other parts of your code have access to it as well; a local stringstream would be an ideal candidate for imbuing with specialized behaviors).
A ‘next item must be a comma’ extractor:
#include <cctype>
#include <iostream>
struct extract
{
char c;
extract( char c ): c(c) { }
};
std::istream& operator >> ( std::istream& ins, extract e )
{
// Skip leading whitespace IFF user is not asking to extract a whitespace character
if (!std::isspace( e.c )) ins >> std::ws;
// Attempt to get the specific character
if (ins.peek() == e.c) ins.get();
// Failure works as always
else ins.setstate( std::ios::failbit );
return ins;
}
int main()
{
int a, b;
std::cin >> a >> extract(',') >> b;
if (std::cin)
std::cout << a << ',' << b << "\n";
else
std::cout << "quiznak.\n";
}
Running this code, the extract manipulator/extractor/whatever will succeed only if the next non-whitespace item is a comma. It fails otherwise.
You can easily modify this to make the comma optional:
std::istream& operator >> ( std::istream& ins, optional_extract e )
{
// Skip leading whitespace IFF user is not asking to extract a whitespace character
if (!std::isspace( e.c )) ins >> std::ws;
// Attempt to get the specific character
if (ins.peek() == e.c) ins.get();
// There is no failure!
return ins;
}
...
std::cin >> a >> optional_extract(',') >> b;
Etc.
[1] cin >> a >> b; is not equivalent to scanf( "%d,%d", ...);. C++ does not magically ignore commas. Just as in C, you must treat them explicitly.
The same for the answer using getline() and a stringstream; while the combination is valid, the actual problem is just shifted from std::cin to another stream object, and still must be treated.
I am getting the following error when using a getline() function:
no instance of overload function "getline" matches the argument list
In one class named "Time" I use it when reading in the following input:
istream & operator >> (istream & input, Time & C) /// An input stream for the hour minutes and seconds
{
char ch;
input >> C.hour >> ch >> C.minute >> ch >> C.second;
getline(input,C.ampm,',');
return input; /// Returning the input value
}
This works fine, but I also want to use it for another class called "Shares":
istream & operator >> (istream & input, Shares & C) /// An input stream for the day, month and year
{
char ch;
input >> C.price >> ch >> C.volume >> ch >> C.value >> ch;
getline(input,C.value,',');
return input; /// Returning the input value
}
However, the getline function in the "shares" class is giving me the error.
Both classes are using the libraries:
#include <iostream>
#include <string>
How can I overcome this?
Thanks
getline(input,C.value,',');
based on the comments, you wrote that C.value is double. That will not fly because as others pointed out, the expected parameter is a string type in there.
You would need to read into a temporary string and then convert it to your double. The latter step is simple, but even simpler with C++11's std::stod.
Therefore, you would be writing something like this:
std::string valueString;
getline(input, valueString, ',');
C.value = std::stod(valueString);
I have this situation where I need to get two int values from each row inside a file with this format:
43=>113
344=>22
Is it possible to do someting like setting a delimiter equal to => and than use >> operator to assign ints?
ifstream iFile("input.in");
int a,b;
iFile >> a >> b;
Also can be done autoamtically to output with similar format?
oFile << a << b;
instead of
oFile << a << "=>" << b;
Thanks.
You can't do it directly, without any extra code when reading or
writing, but you can write a manipulator which handles it for
you more explicitly:
std::istream&
mysep( std::istream& source )
{
source >> std::ws; // Skip whitespace.
if ( source.get() != '=' || source.get() != '>' ) {
// We didn't find the separator, so it's an error
source.setstate( std::ios_base::failbit );
}
return source;
}
Then, if you write:
ifile >> a >> mysep >> b;
, you will get an error is the separator is absent.
On output, you can use a similar manipulator:
std::ostream&
mysep( std::ostream& dest )
{
dest << "=>";
return dest;
}
This has the advantage of keeping the information as to what the
separator is isolated in these two specific functions (which
would be defined next to one another, in the same source file),
rather than spread out where ever you are reading or writing.
Also, these data presumably represent some particular type of
information in your code. If so, you should probably define it
as a class, and then defined operators >> and << over that
class.
Given a and b are variables of inbuilt types, you can not define your own user-defined operators for streaming them (the Standard library already provides such functions).
You could just write out code with the behaviour you want...
int a, b;
char eq, gt;
// this is probably good enough, though it would accept e.g. "29 = > 37" too.
// disable whitespace skipping with <iomanip>'s std::noskipws if you care....
if (iFile >> a >> eq >> gt >> b && eq == '=' && gt == '>')
...
OR wrap a and b into a class or struct, and provider user-defined operators for that. There are plenty of SO questions with answers explaining how to write such streaming functions.
OR write a support function...
#include <iomanip>
std::istream& skip_eq_gt(std::istream& is)
{
char eq, gt;
// save current state of skipws...
bool skipping = is.flags() & std::ios_base::skipws;
// putting noskipws between eq and gt means whatever the skipws state
// has been will still be honoured while seeking the first character - 'eq'
is >> eq >> std::noskipws >> gt;
// restore the earlier skipws setting...
if (skipping)
is.flags(is.flags() | std::ios_base::skipws);
// earlier ">>" operations may have set fail and/or eof, but check extra reasons to do so
if (eq != '=' || gt != '>')
is.setstate(std::ios_base::failbit)
return is;
}
...then use it like this...
if (std::cin >> a >> skip_eq_gt >> b)
...use a and b...
This function "works" because streams are designed to accept "io manipulator" functions that reconfigure some aspect of the stream (for example, std::noskipws), but for a function to be called it just has to match the prototype for an (input) io manipulator: std::istream& (std::istream&).
If you have always have => as the deliminator, you can write a function that will parse lines of the document.
void Parse(ifstream& i)
{
string l;
while(getline(i,l))
{
//First part
string first = l.substr(0, l.find("=>"));
//Second part
string second = l.substr(l.find("=>")+2, l.length());
//Do whatever you want to do with them.
}
}
Hi I'd like to ask how to parse multiple floats, separated by "/" and spaces, from a string.
The text format from the file is "f 1/1/1 2/2/2 3/3/3 4/4/4"
I need to parse every integer from this line of text into several int variables, which are then used to construct a "face" object(see below).
int a(0),b(0),c(0),d(0),e(0);
int t[4]={0,0,0,0};
//parsing code goes here
faces.push_back(new face(b,a,c,d,e,t[0],t[1],t[2],t[3],currentMaterial));
I could do it with sscanf(), but I've been warn away from that by my uni lecturer, so I am looking for an alternative. I am also not allowed other 3rd party libraries, including boost.
Regular expressions and parsing with stringstream() have been mentioned, but I don't really know much about either, and would appreciate some advice.
If you're reading the file with std::ifstream, there's no need for std::istringstream in the first place (although using the two is very similar because they inherit from the same base class). Here's how to do it with std::ifstream:
ifstream ifs("Your file.txt");
vector<int> numbers;
while (ifs)
{
while (ifs.peek() == ' ' || ifs.peek() == '/')
ifs.get();
int number;
if (ifs >> number)
numbers.push_back(number);
}
Taking into account your example f 1/1/1 2/2/2 3/3/3 4/4/4 what you need to read is: char int char int char int int char int char int int char int char int
To do this:
istringstream is(str);
char f, c;
int d[12];
bool success = (is >> f) && (f == 'f')
&& (is >> d[0]) && (is >> c) && (c == '/')
&& (is >> d[1]) && (is >> c) && (c == '/') &&
..... && (is >> d[11]);
The way I would do this is to change the interpretation of space to include the other separators. If I were to get fancy I would use different std::ostream objects, each with a std::ctype<char> facet set up to deal with one separator, and use a shared std::streambuf.
If you want to make the use of separators explicit you could instead use a suitable manipulator to skip the separator or, if it absent, indicate failure:
template <char Sep>
std::istream& sep(std::istream& in) {
if ((in >> std::ws).peek() != std::to_int_type(Sep)) {
in.setstate(std::ios_base::failbit);
}
else {
in.ignore();
}
return in;
}
std::istream& (* const slash)(std::istream&) = Sep<'/'>;
The code isn't tested and type on a mobile device, i.e., probably contains small errors. You'd read data like this:
if (in >> v1 >> v2 >> slash >> v3 /*...*/) {
deal_with_input(v1, v2, v3);
}
Note: the above use assumes input as
1.0 2.0/3.0
i.e. a space after the first value and a slash after the second value.
You can use boost::split.
Sample example is:
string line("test\ttest2\ttest3");
vector<string> strs;
boost::split(strs,line,boost::is_any_of("\t"));
cout << "* size of the vector: " << strs.size() << endl;
for (size_t i = 0; i < strs.size(); i++)
cout << strs[i] << endl;
more information here:
http://www.boost.org/doc/libs/1_51_0/doc/html/string_algo.html
and also related:
Splitting the string using boost::algorithm::split
I'm trying to use an overloaded ">>" to scan input from a file.
The problem is, I have no idea how to deal with end of file.
In this case, my file is composed of a number, followed by several chars
Ex:
9rl
8d
6ff
istream &operator>>(istream &is, Move &move)
{
char c;
int i = 0;
c = is.get();
if (!isalnum(c))
return;
move.setNum(c); // I convert the char to an int, but I'l edit it out
while ( (c = is.get()) != '\n')
{
move.setDirection(i, c); //sets character c into in array at index i
i++;
} // while chars are not newline
return is;
} // operator >>
The test for the character being alpha numeric worked when I had this as a regular function, but doesn't work here as it expects an input stream to be returned. I've tried returning NULL as well. Suggestions?
EDIT: this is being called in a while loop, So i'm trying to figure out some way to have this trigger some flag so that I can break out of the loop. In my previous function, I had this return a boolean, returning true if successful or false if the character was not alphanumeric
Return is. Callers should check the stream for errors.
Be sure to set error bits as appropriate:
std::istream &operator>>(std::istream &is, Move &move)
{
char c;
int i = 0;
c = is.get();
if (is.eof())
return is;
else if (c < '0' || c > '9') {
is.setstate(std::ios::badbit);
return is;
}
else
move.setNum(c-'0');
while ( (c = is.get()) != '\n' && is)
move.setDirection(i++, c);
if (c != '\n')
is.setstate(std::ios::badbit);
return is;
}
Use it as in the following:
int main(int argc, char **argv)
{
std::stringstream s;
s << "9rl\n"
<< "8d\n"
<< "6ff\n";
s.seekg(0);
Move m;
while (s >> m)
std::cout << m;
if (s.bad())
std::cerr << argv[0] << ": extraction failed\n";
return 0;
}
Notice that the code uses the instance m only after successful extraction.
You can set the flags of the stream to a state such as ios::bad or ios::fail using ios::setstate. This will allow the caller to test the stream or in the case that exceptions are enabled for the stream, an exception will be raised.
You also fail to check the state of your stream. The C++ FAQ lite has a great section explaining this. To clarify this I have added the code snippet below.
c = is.get();
// the stream has not been tested to see if it read into c correctly
if (!isalnum(c))
return;