【问题标题】:How to get the last integer of sequence of integers separated by commas in C++?如何获取C++中用逗号分隔的整数序列的最后一个整数?
【发布时间】:2018-10-29 01:54:42
【问题描述】:

我想要做的是从用逗号分隔的整数文件中获取每个整数并添加它们。例如,如果文件包含2,3,4,1,我的程序必须显示总和为 10。为此,我编写了以下代码。

int number_sum(const char* filename) {

std::ifstream file(filename); 

if (file.is_open()) {

    int sum = 0; //sum
    char c; //Store each comma
    int number = 0; //Store each number

    while ( (file >> number >> c) && (c == ',') ) {

        std::cout << "Adding up: " << number << " + " << sum << std::endl;
        sum = sum + number;


    }

    std::cout << "Result is: " << sum << std::endl;

    return sum;
}
else {
    std::cout << "ERROR" << std::endl;
    return -1;
}

这适用于除最后一位以外的所有数字。问题来了是因为最后一个后面没有逗号,所以程序没有搞定。我试图通过检查它是','还是EOF来区分“c”值,但这不起作用。有什么解决方案可以让我的程序获得最后一个数字并将其加到其余数字中吗? (对不起我的英语,不是母语)。

非常感谢您。

【问题讨论】:

  • 使用while (file &gt;&gt; number),并在添加语句后对c进行读取和测试,如果逗号读取不成功,break退出

标签: c++ file integer ifstream


【解决方案1】:

解析字符串比解析文件中的任意数据更容易。从文件中获取单行信息并将其存储到std::string 或读取所有文件并将内容保存到大的bufferstd::vector&lt;std::string&gt;&gt; 中更容易。然后在获得所需的所有信息后,关闭文件句柄,然后就可以进行解析了。

在一些std libraries 的帮助下,您可以相当容易地做到这一点。我们还将使用辅助函数来分解文件中的文本行。

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

std::vector<std::string> split( const std::string& s, char delimiter ) {
    std::vector<std::string> tokens = {};
    std::string token = {};
    std::istringstream tokenStream( s ); // std::istringstream found in <sstream>
    while( std::getline( tokenStream, token, delimiter ) ) {
        tokens.push_back( token );
    }    
    return tokens;
} 

int number_sum( const char* filename ) {
    // First try to open the file; if fails return -1
    std::ifstream file;
    file.open( filename );
    if ( !file.is_open() ) {
        std::cout << "failed to open file " << filename << '\n';
        return -1;
    }

    // read a single line from the file and save it to a local string
    std::string line = {};
    std::getline( file, line );

    // close the file
    file.close();

    // now parse the local string into string tokens and convert them to ints
    std::vector<int> values = {};
    std::vector<std::string> tokens = split( line, ',' );
    for ( auto s : tokens ) {
        values.push_back( std::stoi( s ) ); // std::stoi() found in <string>
    }

    // now that we have our vector of ints parsed from the strings we can add them together
    // std::accumulate() found in <numeric>
    return std::accumulate( values.begin(), values.end(), 0 );
}   

int main() {
    std::cout << number_sum( "test.txt" );

    return 0;
}

test.txt

2,3,4,1

输出

10

使用这种方法,您不必担心是否存在分隔符,这将适用于奇数和偶数类型的情况。当您知道要使用哪些函数时,这就是 stl 库的强大功能。

现在这只会从您的输入文件中执行一行,但可以扩展它以合并来自文件的多行,其中包含一个简单的 while 循环和一个额外的向量来存储每一行​​。不过,您可能必须更改此函数返回的内容。我会把这部分留给你做练习。


在此答案的先前迭代中,我曾提到有一个错误并且我知道它是什么;当我最初发布它时,我正在编写一个辅助函数。只要逗号之间的值是单个数字字符,该程序对每个字符都可以正常工作,并且如果逗号之间有多个值,它将失败或中断。借助此辅助函数通过分隔符将字符串拆分为多个字符串,我们不必担心手动解析字符串中的每个字符,因为 stl 库和函数将为我们完成此操作。此功能现在可以正常工作,并且适用于逗号之间的值超过一位的情况!

test.txt - 2nd 试用

23,32,46,11

输出

112

经过一番考虑,我稍微清理了一下。我不喜欢这样一个事实,即进行累积的函数负责打开和读取文件中的内容,所以我将它移到了它自己的单独函数中。我还喜欢在运行时捕获错误并将它们显示到控制台的能力。最后,我重命名了一个函数,使其更具可读性。这是重构后的程序:

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

std::string readLineFromFile( const char* filename ) {
    std::ifstream file( filename );
    if ( !file ) {
        std::stringstream stream;
        stream << "failed to open file " << filename << '\n';
        throw std::runtime_error( stream.str() );
    }

    std::string line;
    std::getline( file, line );

    file.close();

    return line;
}

std::vector<std::string> splitString( const std::string& s, char delimiter ) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream( s );
    while( std::getline( tokenStream, token, delimiter ) ) {
        tokens.push_back( token );
    }    
    return tokens;
}

int number_sum( const char* filename ) {
    // Get contents from file
    std::string line = readLineFromFile( filename );

    // parse string
    std::vector<int> values;    
    std::vector<std::string> tokens = splitString( line, ',' );
    for( auto s : tokens ) {
        values.push_back( std::stoi( s ) );
    }

    // return the accumulated value
    return std::accumulate( values.begin(), values.end(), 0 );
}

int main() {
    try {
        std::cout << number_sum( "test.txt" ) << '\n';
        // assuming there is no "test2.txt"
        // this will throw a runtime error 
        // and display the appropriate message to the console
        std::cout << number_sum( "test2.txt" ) << '\n';
    } catch( const std::runtime_error& e ) {
        std::cerr << e.what() << '\n';
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

【讨论】:

  • 是的,只要数字是个位数,我的原始方法就可以正常工作,但是当逗号之间的文本文件中的数字是多个数字时;这是错误所在,程序失败了。在我完成这个工作示例之前,我保持原样。现在数据检索和解析已经完成,简单,可移植并且应该没有错误!
【解决方案2】:

在此代码中添加以下行是可行的,但可能需要考虑一些数字

while ( (file >> number >> c) && (c == ',') ) {

    std::cout << "Adding up: " << number << " + " << sum << std::endl;
    sum = sum + number;

}
std::cout << "Adding up: " << number << " + " << sum << std::endl;
sum = sum + number;

这就像暴力破解最后一个,希望它有帮助!

【讨论】:

  • 这将在行不是预期格式的许多情况下添加最后一个数字两次
  • 我想到的第一个如果结尾有逗号,还有其他意想不到的格式吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
相关资源
最近更新 更多