Pregunta

I have a file filled with ints (variable amount on a line), delimited by a space. I would like to parse out the int, then space, then int, then space ... until the newline char then start at a new line until the eof. An example file would look something like this:

1 1 324 234 12 123 
2 2 312 403 234 234 123 125 23 34
...

To grab the ints I can do something like this:

std::ifstream inStream(file.txt);
std::string line;
int myInt = 0;
while(getline(inStream, line)) {
    std::stringstream ss(line);
    while(ss) {
        ss >> myInt;
        //process...
    }
}

My question is that is there an easy way to also get the whitespace and endline char from the ss? Or is my best bet to write my program assuming a space after each index and a newline at the end of the ss? something like this:

std::ifstream inStream(file.txt);
std::string line;
int myInt = 0;
while(getline(inStream, line)) {
    std::stringstream ss(line);
    while(ss) {
        ss >> myInt;
        // process...
        // done with myInt
        char mySpace = ' ';
        // now process mySpace
    }
    char myNewLine = '\n';
    // now process myNewLine
}
¿Fue útil?

Solución

If performance is not the most important issue, the following would be a general-purpose tokenizer for your input format. Whether this is a feasible solution depends of course on what you actually want to do with the input.

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

static void handle_number_string(std::string& literal) {
  if (!literal.empty()) {
    std::istringstream iss {literal};
    int value;
    if (iss >> value) {
      std::clog << "<" << value << ">";
    } else {
      // TODO: Handle malformed integer literal
    }
    literal.clear();
  }
}

int main(int argc, char** argv) {
  for (int i = 1; i < argc; i++) {
    std::string aux;
    std::ifstream istr {argv[i]};
    std::clog << argv[i] << ": ";
    while (istr.good()) {
      const int next = istr.get();
      switch (next) {
      case ' ':
        handle_number_string(aux);
        std::clog << "<SPC>";
        break;
      case '\n':
        handle_number_string(aux);
        std::clog << "<EOL>";
        break;
      default:
        aux.push_back(next);
      }
    }
    // Handle case that the last line was not terminated with '\n'.
    handle_number_string(aux);
    std::clog << std::endl;
  }
  return 0;
}

Addendum: I'd only do this if I absolutely had to. Handling all possibilities (multiple spaces, non-breaking spaces, tabs, \r\n,…) correctly will be a lot of work. If what you actually want to handle are the logical tokens field separator and end of line, manually parsing whitespace seems to be the wrong way to go. It would be sad if your program crashes just because a user has justified the columns in the input file (thus using a variable number of spaces).

Otros consejos

Try something like this:

std::ifstream inStream(file.txt);
std::string line;
int myInt;
while (std::getline(inStream, line))
{
    std::stringstream ss(line);
    ss >> myInt;
    if (ss)
    {
        do
        {
            // process...
            // done with myInt

            ss >> myInt;
            if (!ss) break;

            char mySpace = ' ';
            // now process mySpace
        }
        while (true);
    }

    char myNewLine = '\n';
    // now process myNewLine
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top