3

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.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Ian Young
  • 1,712
  • 1
  • 16
  • 33
  • You want to parse 12 integers, in four sets of three, into nine variables, five seperate and four an in array? How does that make _any_ sense at all? – Mooing Duck Sep 19 '12 at 18:58
  • Though the question doesn't initially look like a duplicate, what you seem to want to do is covered in a previous answer: http://stackoverflow.com/a/2909187/179910 – Jerry Coffin Sep 19 '12 at 19:08

4 Answers4

1

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);
}
user1610015
  • 6,561
  • 2
  • 15
  • 18
1

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]);
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
1

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.

Community
  • 1
  • 1
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

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

Community
  • 1
  • 1
CyberGuy
  • 2,783
  • 1
  • 21
  • 31
  • My apologies. It slipped my mind that I have been told to avoid any non standard libraries (as my lecturer won't have them). – Ian Young Sep 19 '12 at 18:51