I would like to create a function that reads each line of the input and produces its sum and save that as sum.txt using C++

自闭症网瘾萝莉.ら 提交于 2019-12-06 14:45:07

问题


Let's assume that I have the following input:

1 2 3 
5 6
10 11
13

stored in wow.txt.

I would like to create a function that reads each line of the input and produces its sum and save that as sum.txt using C++.

In the input file, we have the following:

1) we don't know the length of each line, but it has at most 10 integers.
2) each integer is separated by a space.

So I started with

ifstream inFile;
inFile.open("wow.txt");
ofstream outFile;
outFile.open("sum.txt");

and wasn't sure what to do next.

Some of my friends recommended me using getline, tokenize each line, and then convert string to integer, but I was wondering if there are easier ways of doing it without having to change the type (int to string, string to int) back and forth.

Any help would be greatly appreciated.


回答1:


Using getline and istringstream:

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

using namespace std;

int main() {
  ifstream inFile("wow.txt");
  if (!inFile) {
    cerr << "File wow.txt not found." << endl;
    return -1;
  }
  ofstream outFile("sum.txt");

  // Using getline() to read one line at a time.
  string line;
  while (getline(inFile, line)) {
    if (line.empty()) continue;

    // Using istringstream to read the line into integers.
    istringstream iss(line);
    int sum = 0, next = 0;
    while (iss >> next) sum += next;
    outFile << sum << endl;
  }

  inFile.close();
  outFile.close();
  return 0;
}

Output:

6
11
21
13



回答2:


I'm not a big fan of the std::getline() and then use std::istringstream approach: streams aren't free to create. At the very least, the inner `std::istringstream should be constructed once and then be reset, even though this requires to clear the flags:

std::istringstream iss;
for (std::string line; std::getline(std::cin, line); ) {
    iss.clear();
    iss.str(line);
    // ...
}

The call to iss.clear() resets the stream's error flags which get set to eventually indicate that there is no more data. With iss.str(line) the string stream's internal data is set.

Instead of creating or setting an std::istringstream I would arrange for the newline to set the input stream to be false, i.e., to have std::ios_base::failbit set. For the advanced approach to do so, I'd change the definition of whitespace for the std:ctype<char> facet in the std::locale used by the stream. However, that's shooting the big guns! For the task at hand, a simple manipulator used before each input can be used to a similar effect:

#include <iostream>
#include <cctype>

using namespace std;

std::istream& skipspace(std::istream& in) {
    while (std::isspace(in.peek())) {
        int c(in.peek());
        in.ignore();
        if (c == '\n') {
            in.setstate(std::ios_base::failbit);
            break;
        }
    }
    return in;
}

int main() {
    int sum(0);
    while (std::cin >> sum) {
        for (int value; std::cin >> skipspace >> value; ) {
            sum += value;
        }
        std::cout << "sum: " << sum << "\n";
        std::cin.clear();
    }
    return 0;
}

Most of the magic is in the manipulator skipspace(): it skips whitespace until either the end of the stream is reached or a newline is consumed. If a newline is consumed, it puts the stream into failure state by setting the flag std::ios_base::failbit.

The loop computing the sum simply reads the first value. If this fails, e.g., because a non-integer is found, the input fails and no further output is generated. Otherwise whitespace is skipped using the skipspace() followed by reading the next value. If either of these fails, the current sum is printed and the stream is cleared for the next sum to be read.



来源:https://stackoverflow.com/questions/24987600/i-would-like-to-create-a-function-that-reads-each-line-of-the-input-and-produces

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!