tags:

views:

298

answers:

7

C++ is not my preferred language.

I have a file that contains this:

e 225,370 35,75

I want to separate e, 225, 370, 35 and 75 from each other into a char and ints but I'm having trouble. I tried doing everything I found online and in my C++ book and still it's not working out. Please help.

I would have an easier time doing this in Java.

A: 

Assuming that you've read the data into a strings ...

  1. strchr is like String.index.
  2. strtol is like Integer.parseInt()

What else do you need?

bmargulies
strtok would be more convenient than strchr
Emile Cormier
`strtok` isn't thread-safe, though, if that's a concern.
greyfade
+1  A: 
#include <fstream>

/* ... */

ifstream file;
file.open("yourfile.txt");
char c, dummy;
int i[4];
file >> c >> i[0] >> dummy >> i[1] >> i[2] >> dummy >> i[3];
file.close();
Peter Alexander
I'm not certain of the behavior, as I'm not a C++ programmer, but I would be surprised if this just ignored the commas in the file. Does it?
danben
@danben:it can, but by default it won't. Even most dedicated C++ programmers never touch the parts of the library necessary to get it to ignore the commas (you have to create a custom `ctype facet`, create a `locale` containing that `facet`, then `imbue` the stream with that `locale`).
Jerry Coffin
@danden, You're right. I have updated my solution.
Peter Alexander
A: 
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
        ifstream f("a.txt"); // check for errors.

        char ch,dummy;
        int i1,i2,i3,i4;

        f>>ch>>i1>>dummy>>i2>>i3>>dummy>>i4;

        cout<<ch<<endl<<i1<<endl<<i2<<endl<<i3<<endl<<i4<<endl;

        return 0;
}
codaddict
A: 

If you have control over the format, it'll be (slightly) easier to read if you eliminate the commas, and just have input like

e 225 370 35 75

With this format, Poita_'s code for reading the data will work [edit: he's since update his code to explicitly read and skip the commas]. Otherwise, you'll need to explicitly skip over the commas:

char ingore1, ignore2;
char ch;
int i[4];

file >> ch >> i[0] >> ignore1 >> i[1] >> i[2] >> ignore2 >> i[3];

[Edit: if you're paranoid or really need to verify your input, at this point you can check that ignore1 and ignore2 contain commas.]

In most cases, however, the data are probably related, so you'll want to read an entire line into a single struct (or class):

struct data { 
    char ch;
    int i[4];

    std::istream &operator>>(std::istream &is, data &d) { 
        char ignore1, ignore2;
        return is >> ch >> i[0] >> ignore1 >> i[1] >> i[2] >> ignore2 >> i[3];
    }
};

Having done this, you can read an entire data object at a time:

std::ifstream infile("my data file.txt");
data d;

infile >> d;

Or, if you have a whole file full of these, you can read them all into a vector:

std::vector<data> d;

std::copy(std::istream_iterator<data>(infile), 
    std::istream_iterator<data>(),
    std::back_inserter(d));
Jerry Coffin
Nice one. I'm usually messing with string's find and substr methods.
StackedCrooked
A: 

If you want to use the old fashioned C runtime

FILE * pf = fopen(filename, "r");
char e;
int  a, b, c, d;
int ii = fscanf(pf, "%c %d,%d %d,%d", &e, &a, &b, &c, &d);
if (ii < 5) 
   printf("problem in the input file");
fclose (pf);

edit: added error checking based on comment from dreamlax

John Knoeller
This one is very clean-looking. Although, be sure to check that the return value of `fscanf` is 5 to ensure that all variables were assigned appropriately.
dreamlax
In these situations I believe fscanf to be superior to the C++ ways.
StackedCrooked
What is up with all of the drive by markdowns on this answer? current score is +4 -3, and not a single markdown willing to explain why.
John Knoeller
@John Knoeller: I think it may be because the answer is more `C` than `C++`.
dreamlax
+1  A: 

Use Boost Tokenizer to split the string. I am assuming that only the first token is a char, so sample code would be something like:

#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
#include <vector>

using namespace std;

...

typedef boost::tokenizer<boost::char_separator<char> > tokenizer;

string teststring("e 225,370 35,75");
boost::char_separator<char> separators(", ");
tokenizer tokens(teststring, separators);
vector<string> substrings;
for (tokenizer::iterator iter = tokens.begin(); iter != tokens.end(); ++iter)
{
    substrings.push_back(*iter);
}

and, voila, you have all of your substrings in a neat vector. The char is in substrings[0] as a std::string, and the following int values are in substrings[1] and those following, also as std::string. You will need to convert them to integer values. For this I suggest you look at stringstream.

Demi
Boost libraries can be found here: http://www.boost.org/users/download/
Demi
+4  A: 

The String Toolkit Library (Strtk) has the following solution to your problem:

int main()
{ 
   std::string data("e 225,370 35,75");
   char c1;
   int i1,i2,i3,i4;
   strtk::parse(data,", ",c1,i1,i2,i3,i4);
   return 0;
}

More examples can be found Here

Beh Tou Cheh