20

Suppose I have an input file in this format:

VAL1 VAL2 VAL3
VAL1 VAL2 VAL3

I'm writing a program that would be interested only in VAL1 and VAL3. In C, if i wanted to 'skip' the second value, I'd do as follows:

char VAL1[LENGTH]; char VAL3[LENGTH];
FILE * input_file;
fscanf(input_file, "%s %*s %s", VAL1, VAL3);

Meaning, I'd use the "%*s" formatter to make fscanf() read this token and skip it. How do I do this with C++'s cin? Is there a similar command? Or do I have to read to a dummy variable?

Thanks in advance.

Rafael Almeida
  • 10,352
  • 6
  • 45
  • 60

5 Answers5

14

The C++ String Toolkit Library (StrTk) has the following solution to your problem:

#include <string>
#include <deque>
#include "strtk.hpp"

int main()
{
   struct line_type
   {
      std::string val1;
      std::string val3;
   };

   std::deque<line_type> line_list;

   const std::string file_name = "data.txt";

   strtk::for_each_line(file_name,
                        [&line_list](const std::string& line)
                        {
                           strtk::ignore_token ignore;
                           line_type temp_line;
                           const bool result = strtk::parse(line,
                                                            " ",
                                                            temp_line.val1,
                                                            ignore,
                                                            temp_line.val3);
                           if (!result) return;
                           line_list.push_back(temp_line);
                        });

   return 0;
}

More examples can be found Here

7

There's an ignore function available:

std::cin << val1;
std::cin.ignore (9999, ' ');
std::cin << val3;

The first argument defines the number of characters to skip, the second parameter is the delimiter to stop skipping at.

You could wrap that up in a user-defined manipulator, since it's ugly.


Here's the custom manipulator:

template <class charT, class traits>
inline std::basic_istream<charT, traits> &
ignoreToken (std::basic_istream<charT, traits> &strm)
{
    strm.ignore (9999, ' ');
    return strm;
}

And you could use that like this:

cin >> val1 >> ignoreToken >> val3 >> ignoreToken >> val5;

(ps -- I didn't compile this, so there maybe a typo).

eduffy
  • 39,140
  • 13
  • 95
  • 92
  • This is VERY close to what I want. But is there no way to ignore ANY number of characters (or a whitespace), instead of fixing a really big value? – Rafael Almeida Jun 11 '09 at 20:39
  • Nope. You gotta supply a big number. Some of the docs I've read recommend using "std::numerical_limits::max()", but (IMO) that's just silly. – eduffy Jun 11 '09 at 20:42
  • 1
    std::numeric_limits::max() PS. Its not silly, its defensive programming. – Martin York Jun 11 '09 at 23:50
  • 2
    What is silly is forcing yourself using something that stinks (C++ streams IO) just because it's there. Actually IMO what is really horrible is output formatting, but even input is not that great. – 6502 Dec 30 '10 at 20:51
2

You can do it in a much easier way with getline(). Just use it to grab the entire line, and then parse out the values in between the tokens (use strtok?)

There are a whole bunch of other issues with getline(), but it should work for your problem.

SuPra
  • 8,488
  • 4
  • 37
  • 30
1

I would just read it into a dummy variable. If you do need it eventually, it will be available.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
  • Of course this is my 'default' choice, but I'm willing to avoid it since there will be many (circa 10) tokens I don't want. Plus, there is also my own curiosity of trying to do the thing in a 'beautiful' way. I kind of refuse to believe that something already present in C wasn't considered in the design of C++. – Rafael Almeida Jun 11 '09 at 20:33
0

You can use

cin.ignore(256, ' ');

This will ignore everything up to either 256 characters or a white space.

Edit (formatting and...): alternatives you can do:

int a, b;
cin >> a >> b >> b;
Niki Yoshiuchi
  • 16,883
  • 1
  • 35
  • 44