Проанализировать строку проще, чем произвольные данные из файла. Проще взять одну строку информации из файла и сохранить ее в 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;
}
test.txt
2,3,4,1
выход
10
При таком подходе вам не нужно беспокоиться об учете разделителей, находящихся там или не присутствующих, это будет учитывать как случаи нечетного, так и четного типа. Это сила библиотеки stl
, когда вы знаете, какие функции использовать.
Теперь это будет делать только одну строку из вашего входного файла, но это может быть расширено для включения нескольких строк из файла с простым циклом while и дополнительным вектором для хранения каждой строки. Возможно, вам придется изменить то, что возвращает эта функция. Я оставлю эту часть в качестве упражнения для вас.
В предыдущей итерации этого ответа я упоминал, что была ошибка, и я знал, что это было; Я был в процессе написания вспомогательной функции, когда я первоначально разместил ее. Программа работала нормально для каждого символа, если значение между запятыми представляло собой однозначный символ, и оно не работало или ломалось, если между запятыми было более одного значения. С помощью этой вспомогательной функции для разделения строки на несколько строк через разделитель нам не нужно беспокоиться о ручном разборе каждого символа в строке, поскольку библиотека stl
и функции сделают это за нас. Эта функция теперь работает правильно и подходит для случаев, когда значения между запятыми имеют более одной цифры!
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;
}