I am new to c++.My aim is to read a file containing all integers, like
1 2 3\n 1 3 4\n 1 2 4\n
and
1,2 3,4 5,6\n 1,3 3,4 3,5\n 1,3 3,4 4,2\n
I could use getline to read them, but how could I split it into an integer array. Like array[3]={1,2,3} and array2={1,2,3,4,5,6} for the first line reading result? Sorry I forgot to mention that I was trying to not use the STLs for C++
You can do it without boost spirit
// for single line:
std::vector<int> readMagicInts(std::istream &input)
{
std::vector<int> result;
int x;
while(true) {
if (!(input >> x)) {
char separator;
input.clear(); // clear error flags;
if (!(input >> separator >> x)) break;
if (separator != ',') break;
}
result.push_back(x);
}
return result;
}
std::vector<std::vector<int>> readMagicLinesWithInts(std::istream &input)
{
std::vector<std::vector<int>> result;
std::string line;
while (std::getline(input, line)) {
std::istringstream lineData(line);
result.push_back(readMagicInts(lineData));
}
return result;
}
I want to read an input like this from file
sphere 3 2 3 4
pyramid 2 3 4 12 3 5 6 7 3 2 4 1 2 3
rectangle 2 3 4 1 9 12
I want to do something like this
char name[64];
int arr[12];
ifstream file (..);
while(file)
{
file >> name;
while( //reach end of line)
file >> arr[i]
}
As you can see I don't know how many integers will be entered, that's why I want to stop at new line. I did it with getline, and then splitting the line, but they told me it can be done only with >> operator.
Note: I can't use std::string or std::vector.
The simple version is to use a manipulator similar to std::ws but instead of skipping all whitespace setting std::ios_base::failbit when a newline is encountered. This manipulator would then be used to instead of skipping whitespace implicitly whitespace other than newlines are skipped. For example (the code isn't test but I think something like this with the bugs and compilation errors removed should work):
std::istream& my_ws(std::istream& in) {
std::istream::sentry kerberos(in);
while (isspace(in.peek())) {
if (in.get() == '\n') {
in.setstate(std::ios_base::failbit);
}
}
return in;
}
// ...
char name[64];
int array[12];
while (in >> std::setw(sizeof(name)) >> name) { // see (*) below
int* it = std::begin(array), end = std::end(array);
while (it != end && in >> my_ws >> *it) {
++it;
}
if (it != end && in) { deal_with_the_array_being_full(); }
else {
do_something_with_the_data(std::begin(array), it);
if (!in.eof()) { in.clear(); }
}
}
My personal guess is that the assignment asked for reading the values into char arrays followed by converting them using atoi() or strol(). I think that would be a boring solution to the exercise.
(*) Never, not even in exmaple code, use the formatted input operator with a char array array without also setting the maximum allowed size! The size can be set by setting the stream's width(), e.g., using the manipulator std::setw(sizeof(array)). If the width() is 0 when using the formatted input operator with a char array, an arbitrary number of non-whitespace characters is read. This can easily overflow the array and become a security problem! Essentially, this is the C++ way of spelling C's gets() (which is now removed from both the C and the C++ standard libraries).
I suppose that you can use peek method:
while (file)
{
file >> name;
int i = 0;
while(file.peek() != '\n' && file.peek() != EOF) {
file >> arr[i++];
}
}
If I'm reading in lines from a .txt file of varying length, (i.e. 5 integers on line 1, then 2 integers on line 2, then 10 integers on line 3, and etc.), using fgets (although I don't necessarily need to use it, just seemed like a good tool in my situation). Every solution I find returns an error of 0 (like strtol or atio).
char str[100];
char* p = str;
FILE* fp;
fp = open("text.txt",r);
if(fp == NULL)
printf("aborting.. Cannot open file! \n");
while(!foef(fp))
{
if(fgets(p,100,fp) != NULL)
{
for (int j = 0 ; j < 20 ; j+=2)
{
temp1 = strtol(p, &p, 10);
// need to store temp1 into arr[j] if it is a valid integer (0->inf)
// but should discard if we are at the end of the line
}
}
Ben's answer was so good, it should be part of the answer
Set errno to 0 before calling strtol.
Check errno. From man page
ERANGE
The resulting value was out of range.
The implementation may also set errno to EINVAL in case no conversion was performed (no digits seen, and 0 returned).
You could actually use C++:
std::ifstream file("text.txt");
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
int i;
while (iss >> i) {
// ...
}
}
The inner loop could simply load all of the ints into a vector directly or something:
std::ifstream file("text.txt");
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
std::vector<int> all_the_ints{
std::istream_iterator<int>{iss},
std::istream_iterator<int>{}
};
}
You're throwing away the information available from strtol.
In particular, after a call
val = strtol(p, &endp, radix);
you are interested in whether p == endp.
In your call strtol(p, &p, radix) you're overwriting p too soon and losing the chance to perform the test.
if i have a file like
1 5 6 9 7 1
2 5 4 3 8 9
3 4 3 2 1 6
4 1 3 6 5 4
and i want to sort the numbers in every line ..
how to know when there is a newline ?
code for example :
while (!input.eof) {
input>>num;
while (not new line ?){
input>>o;
b.push_back(o);
}
sort (b.begin(),b.end());
se=b.size();
output<<num<<" "<<b[se-1]<<endl;
b.clear();
}
Note: i tried while(input>>num) and getline will now work with me
any ideas ?
Your input doesn't work! Using a loop testing for stream.eof() as the only control for the input is always wrong. You always need to test your input after you tried to read it. Incidentally, I posted earlier how you can guarantee that there is no newline between to objects. there is already an answer using std::getline() as a first stage which is somewhat boring. Here is an alternate approach:
std::istream& noeol(std::istream& in) {
for (int c; (c = in.peek()) != std::char_traits<char>::eof()
&& std::isspace(c); in.get()) {
if (c == '\n') {
in.setstate(std::ios_base::failbit);
}
}
return in;
}
// ...
while (input >> num) {
do {
b.push_back(num);
} while (input >> noeol >> num);
std::sort (b.begin(),b.end());
se=b.size();
output<<num<<" "<<b[se-1]<<endl;
b.clear();
input.clear();
}
You can use std::getline together with std::istringstream to read the file line by line, and then process each line individually:
#include <sstream>
std::string line;
while (std::getline(infile, line))
{
std::istringstream iss(line);
int a, b;
//You can now read the numbers in the current line from iss
}
For further reference on how to read the file line by line, see this post.
I have a file with data listed as follows:
0, 2, 10
10, 8, 10
10, 10, 10
10, 16, 10
15, 10, 16
17, 10, 16
I want to be able to input the file and split it into three arrays, in the process trimming all excess spaces and converting each element to integers.
For some reason I can't find an easy way to do this in c++. The only success I've had is by inputting each line into an array, and then regexing out all the spaces and then splitting it up. This entire process took me a good 20-30 lines of code and its a pain to modify for say another separator(eg. space), etc.
This is the python equivalent of what I would like to have in C++:
f = open('input_hard.dat')
lines = f.readlines()
f.close()
#declarations
inint, inbase, outbase = [], [], []
#input parsing
for line in lines:
bits = string.split(line, ',')
inint.append(int(bits[0].strip()))
inbase.append(int(bits[1].strip()))
outbase.append(int(bits[2].strip()))
The ease of use of doing this in python is one of the reasons why I moved to it in the first place. However, I require to do this in C++ now and I would hate to have to use my ugly 20-30 line code.
Any help would be appreciated, thanks!
There's no real need to use boost in this example as streams will do the trick nicely:
int main(int argc, char* argv[])
{
ifstream file(argv[1]);
const unsigned maxIgnore = 10;
const int delim = ',';
int x,y,z;
vector<int> vecx, vecy, vecz;
while (file)
{
file >> x;
file.ignore(maxIgnore, delim);
file >> y;
file.ignore(maxIgnore, delim);
file >> z;
vecx.push_back(x);
vecy.push_back(y);
vecz.push_back(z);
}
}
Though if I were going to use boost I'd prefer the simplicity of tokenizer to regex... :)
There is really nothing wrong with fscanf, which is probably the fastest solution in this case. And it's as short and readable as the python code:
FILE *fp = fopen("file.dat", "r");
int x, y, z;
std::vector<int> vx, vy, vz;
while (fscanf(fp, "%d, %d, %d", &x, &y, &z) == 3) {
vx.push_back(x);
vy.push_back(y);
vz.push_back(z);
}
fclose(fp);
Something like:
vector<int> inint;
vector<int> inbase;
vector<int> outbase;
while (fgets(buf, fh)) {
char *tok = strtok(buf, ", ");
inint.push_back(atoi(tok));
tok = strtok(NULL, ", ");
inbase.push_back(atoi(tok));
tok = strtok(NULL, ", ");
outbase.push_back(atoi(tok));
}
Except with error checking.
why not the same code as in python :) ?
std::ifstream file("input_hard.dat");
std::vector<int> inint, inbase, outbase;
while (file.good()){
int val1, val2, val3;
char delim;
file >> val1 >> delim >> val2 >> delim >> val3;
inint.push_back(val1);
inbase.push_back(val2);
outbase.push_back(val3);
}
std::getline allows you to read a line of text, and you can use a string stream to parse the individual line:
string buf;
getline(cin, buf);
stringstream par(buf);
char buf2[512];
par.getline(buf2, 512, ','); /* Reads until the first token. */
Once you get the line of text into the string, you can actually use any parsing function you want, even sscanf(buf.c_str(), "%d,%d'%d", &i1, &i2, &i3), by using atoi on the substring with the integer, or through some other method.
You can also ignore unwanted characters in the input stream, if you know they're there:
if (cin.peek() == ',')
cin.ignore(1, ',');
cin >> nextInt;
If you don't mind using the Boost libraries...
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
std::vector<int> ParseFile(std::istream& in) {
const boost::regex cItemPattern(" *([0-9]+),?");
std::vector<int> return_value;
std::string line;
while (std::getline(in, line)) {
string::const_iterator b=line.begin(), e=line.end();
boost::smatch match;
while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
return_value.push_back(boost::lexical_cast<int>(match[1].str()));
b=match[0].second;
};
};
return return_value;
}
That pulls the lines from the stream, then uses the Boost::RegEx library (with a capture group) to extract each number from the lines. It automatically ignores anything that isn't a valid number, though that can be changed if you wish.
It's still about twenty lines with the #includes, but you can use it to extract essentially anything from the file's lines. This is a trivial example, I'm using pretty much identical code to extract tags and optional values from a database field, the only major difference is the regular expression.
EDIT: Oops, you wanted three separate vectors. Try this slight modification instead:
const boost::regex cItemPattern(" *([0-9]+), *([0-9]+), *([0-9]+)");
std::vector<int> vector1, vector2, vector3;
std::string line;
while (std::getline(in, line)) {
string::const_iterator b=line.begin(), e=line.end();
boost::smatch match;
while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
vector1.push_back(boost::lexical_cast<int>(match[1].str()));
vector2.push_back(boost::lexical_cast<int>(match[2].str()));
vector3.push_back(boost::lexical_cast<int>(match[3].str()));
b=match[0].second;
};
};
If you want to be able to scale to harder input formats, you should consider spirit, boost parser combinator library.
This page has an example which almost do what you need (with reals and one vector though)