如何获取C ++中用逗号分隔的整数序列的最后一个整数? [英] How to get the last integer of sequence of integers separated by commas in C++?

查看:83
本文介绍了如何获取C ++中用逗号分隔的整数序列的最后一个整数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What I'm trying to do is to get each integer from a file of integers separated by commas and add them. For example, if the file contains 2,3,4,1 my program has to display that the sum is 10. For that, I wrote the following code.

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"值,但这没有用.有什么解决方案可以使我的程序获取最后一个数字并将其加到其余的数字上吗? (对不起我的英语,不是母语).

This works well with all the digits except the last one. The problem comes because the last one is not followed by a comma, so the program does not get it. I've tried to discriminate "c" value by checking whether it is ',' or EOF, but this didn't work. Is there any solution so that my program can get the last number and add it up to the rest? (Sorry for my english, not native).

非常感谢您.

推荐答案

与从文件中获取任意数据相比,解析字符串要容易得多.从文件中获取单行信息并将其存储到std::string中或读取所有文件并将内容保存到大型bufferstd::vector<std::string>>中都比较容易.然后,在获得所需的所有信息之后,关闭文件句柄,然后该进行解析了.

It is easier to parse a string than arbitrary data from a file. It is easier to grab either a single line of information from a file and store that into an std::string or to read all of the file and save the contents into either a large buffer or a std::vector<std::string>>. Then after you have all the information you need, close the file handle and then it is time to do your parsing.

借助其中一些std libraries,您可以轻松完成此操作.我们还将使用一个辅助函数来分解文件中的文本行.

With the help of a few of the std libraries out there you can do this fairly easy. We will also use a helper function to breakdown our line of text from the file.

#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库的强大功能.

With this approach you don't have to worry about accounting for delimiters either being there or not being there, this will accommodate for both odd and even type cases. This is the power of the stl library when you know what functions to use.

现在,这将只对输入文件执行单行操作,但是可以对其进行扩展以通过简单的while循环和一个额外的向量来存储文件中的多行并入文件中的多行.您可能必须更改此函数返回的内容.我将把这部分留给您练习.

Now this will only do a single line from your input file, but this can be expanded upon to incorporate multiple lines from a file with a simple while loop and an extra vector to store each line. You may have to change what this function returns though. I'll leave that part as an exercise for you.

在此答案的上一次迭代中,我提到过一个错误,并且我知道它是什么.最初发布该函数时,我正在编写一个辅助函数.只要逗号之间的值是一位数字字符,该程序对于每个字符都可以正常工作,如果逗号之间的值不止一个,则该程序将失败或中断.借助于此辅助函数,可以通过定界符将一个字符串分割成多个字符串,我们不必担心手动解析字符串中的每个字符,因为stl库和函数将为我们做到这一点.此功能现在可以正常使用,并且在逗号之间的值超过一位时可以使用!

In a previous iteration of this answer I had mentioned there was a bug and that I knew what it was; I was in the process of writing a helper function when I originally posted it. The program worked fine for each character as long as the value between commas was a single digit character and it would fail or break if there was more than one value between commas. With the aid of this helper function to split a string into multiple strings via a delimiter we don't have to worry about manually parsing each character in the string as the stl library and functions will do this for us. This function is now working correctly and is accommodating for when the values between commas are more than one digit!

test.txt -2 nd 试用版

23,32,46,11

输出

112


经过深思熟虑,我对此做了一些整理.我不喜欢这样的事实,即进行累加的函数负责处理从文件中打开和读取内容的责任,因此我将其移到了自己的单独函数中.我还喜欢在运行时捕获错误并将其显示到控制台的功能.最后,我将函数重命名为更具可读性的描述性代码.这是重构后的程序:


After some consideration I cleaned this up a bit. I didn't like the fact that the function that does the accumulation was handling the responsibility of opening and reading the contents from the file so I moved that to its own separate function. I also like the ability to catch errors during runtime and to display them to the console. Finally I renamed a function to be a little more descriptive for readability. Here is the refactored program:

#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 ++中用逗号分隔的整数序列的最后一个整数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆