c++ - 如何在 C++ 中获取以逗号分隔的整数序列的最后一个整数?

标签 c++ file integer ifstream

我想做的是从以逗号分隔的整数文件中获取每个整数并将它们相加。例如,如果文件包含 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”值,但这没有用。是否有任何解决方案可以让我的程序获得最后一个数字并将其添加到其余部分? (抱歉我的英语不是母语)。

非常感谢您。

最佳答案

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

在一些 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;
}

测试.txt

2,3,4,1

输出

10

使用这种方法,您不必担心是否存在定界符,这将适用于奇数和偶数类型的情况。这就是 stl 的力量当您知道要使用哪些函数时,就可以使用库。

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


在这个答案的前一次迭代中,我提到有一个错误,我知道它是什么;当我最初发布它时,我正在编写一个辅助函数。只要逗号之间的值是一位数字字符,程序就可以很好地处理每个字符,如果逗号之间有多个值,程序就会失败或中断。借助此辅助函数,通过分隔符将字符串拆分为多个字符串,我们不必担心手动将字符串中的每个字符解析为 stl。 library 和 functions 将为我们做这件事。此功能现在可以正常工作,并且适用于逗号之间的值超过一位数的情况!

test.txt - 第 2 试验

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;
}

关于c++ - 如何在 C++ 中获取以逗号分隔的整数序列的最后一个整数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53037772/

相关文章:

c++ - 了解神秘的C++语句

java - Libgdx 读取 Android 的内部文本文件

java - 未知数据类型声明

algorithm - 使用整数项计算矩阵幂

c++ - 比较 C++20 中的多态类型

c++ - 如何在不继承句柄的情况下 fork 进程?

python - 在一行上组合并打印不同的变量

file - 在应用程序中存储电子邮件的设计方法

xml - XSD maxLength 和 minLength 应用于整数

c++ - 关于传递给函数后指针重用的问题