Работая над проблемами такого рода, мне нравится разбивать их на части, связанные с синтаксическим анализом. Я использую некоторые стандартные библиотеки, чтобы сделать часть работы для меня. Я также создал несколько структур, чтобы помочь сохранить информацию об организованных данных. Что касается вашей даты, я мог бы оставить это как один std::string
, но я решил разбить date
на три отдельных типа и сохранить их в структуре данных, чтобы показать возможности одной из функций, которая является связан с разбором.
Что я предпочитаю делать, так это получать либо одну строку данных из файла и сохранять ее в строку, либо получать все содержимое файла и сохранять ее либо в большом буфере, либо в векторе строк, если только Я работаю с конкретным типом кода, где это не применимо, например, при разборе файла wav
. Затем закройте файл руки, как я закончил чтение из него! Затем, после того, как у меня будет вся необходимая информация, вместо того, чтобы пытаться анализировать файл напрямую, когда он открыт, я бы предпочел проанализировать строку, так как ее легче проанализировать. Затем после анализа строки мы можем заполнить наши типы данных, которые нам нужны.
Мне пришлось немного изменить ваш файл данных, чтобы учесть дополнительные пробелы, поэтому я сохранил ваш файл как текстовый файл с одним пробелом между каждым типом данных в одной строке текста. Я также не включил в первую строку (заголовок) информацию, так как я просто опустил ее полностью. Однако это все равно должно служить руководством к разработке хорошего рабочего процесса для приложения, которое имеет хорошую читаемость, возможность повторного использования, старается сделать его переносимым и максимально универсальным. Теперь, чего вы ждали; демонстрация моей версии вашего кода:
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <exception>
struct Date {
int month;
int day;
int year;
Date() = default;
Date( int monthIn, int dayIn, int yearIn ) :
month( monthIn ),
day( dayIn ),
year( yearIn )
{}
};
struct DataSheetItem {
int itemNumber;
Date date;
int quantity;
double costPerEach;
DataSheetItem() = default;
DataSheetItem( int itemNumberIn, Date& dateIn, int quantityIn, double costPerEachIn ) :
itemNumber( itemNumberIn ),
date( dateIn ),
quantity( quantityIn ),
costPerEach( costPerEachIn )
{}
};
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;
}
void getDataFromFile( const char* filename, std::vector<std::string>& output ) {
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;
while( std::getline( file, line ) ) {
if ( line.size() > 0 )
output.push_back( line );
}
file.close();
}
DataSheetItem parseDataSheet( std::string& line ) {
std::vector<std::string> tokens = splitString( line, ' ' ); // First parse with delimeter of a " "
int itemNumber = std::stoi( tokens[0] );
std::vector<std::string> dateInfo = splitString( tokens[1], '/' );
int month = std::stoi( dateInfo[0] );
int day = std::stoi( dateInfo[1] );
int year = std::stoi( dateInfo[2] );
Date date( month, day, year );
int quantity = std::stoi( tokens[2] );
double cost = std::stod( tokens[3] );
return DataSheetItem( itemNumber, date, quantity, cost );
}
void generateDataSheets( std::vector<std::string>& lines, std::vector<DataSheetItem>& dataSheets ) {
for( auto& l : lines ) {
dataSheets.push_back( parseDataSheet( l ) );
}
}
int main() {
try {
std::vector<std::string> fileConents;
getDataSheetItemsFromFile( "test.txt", fileContents );
std::vector<DataSheetItem> data;
generateDataSheets( fileConents, data );
// test to see if info is correct
for( auto& d : data ) {
std::cout << "Item #: " << d.itemNumber << " Date: "
<< d.date.month << "/" << d.date.day << "/" << d.date.year
<< " Quantity: " << d.quantity << " Cost: " << d.costPerEach << '\n';
}
} catch( const std::runtime_error& e ) {
std::cerr << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
ПРИМЕЧАНИЕ Это не будет работать с вашим текущим файлом; это не учитывает первую строку текста (информация заголовка), и это не учитывает никаких дополнительных пробелов между полями данных. Если вы добавляете одну строку текста при открытии файла и читаете в одной строке и просто игнорируете ее, то выполните цикл, чтобы получить все строки, добавляемые в вектор, для возврата назад; Ваши векторы будут содержать информацию, но они не будут в правильных местоположениях индекса вектора из-за всех лишних пробелов. Это то, что вам нужно знать! Кроме этого; это то, как я бы в основном разработал программу или приложение для анализа данных. Это ни в коем случае не является 100% полным доказательством и может даже не быть на 100% свободным от ошибок, но после быстрого бега и запуска его через мой отладчик несколько раз, кажется, без каких-либо заметных ошибок. Также могут быть возможности для улучшения эффективности времени выполнения и т. Д., Но это всего лишь обобщение базового анализа.