22
33#include < fstream>
44#include < iostream>
5- #include < istream>
65#include < sstream>
7- #include < stdexcept>
86
9- BitcoinExchange::BitcoinExchange () {
10- // Constructor implementation
11- }
7+ BitcoinExchange::BitcoinExchange () {}
8+
9+ BitcoinExchange::BitcoinExchange ( const BitcoinExchange& src) { * this = src; }
1210
13- BitcoinExchange::~BitcoinExchange () {
14- // Destructor implementation
11+ BitcoinExchange& BitcoinExchange::operator =(const BitcoinExchange& rhs) {
12+ if (this != &rhs) {
13+ this ->_data = rhs._data ;
14+ }
15+ return *this ;
1516}
1617
17- BitcoinExchange::BitcoinExchange (const BitcoinExchange &other) : data(other.data) {
18- // Copy constructor implementation
18+ BitcoinExchange::~BitcoinExchange () {}
19+
20+ BitcoinExchange::BitcoinExchange (const std::string& dbPath) {
21+ std::ifstream dbFile (dbPath.c_str ());
22+ if (!dbFile.is_open ()) {
23+ throw std::runtime_error (" Error: could not open database file." );
24+ }
25+
26+ std::string line;
27+ std::getline (dbFile, line);
28+
29+ if (line != " date,exchange_rate" ) {
30+ std::cerr << " Error: bad database format." << std::endl;
31+ }
32+
33+ while (std::getline (dbFile, line)) {
34+ std::stringstream ss (line);
35+ std::string date;
36+ std::string rateStr;
37+ float rate;
38+
39+ if (std::getline (ss, date, ' ,' ) && std::getline (ss, rateStr)) {
40+ char * end;
41+ rate = std::strtof (rateStr.c_str (), &end);
42+ if (*end == ' \0 ' ) this ->_data [date] = rate;
43+ }
44+ }
1945}
2046
21- BitcoinExchange &BitcoinExchange::operator =(const BitcoinExchange &other) {
22- if (this != &other) {
23- data = other.data ;
47+ bool BitcoinExchange::_isValidDate (const std::string& date) {
48+ if (date.length () != 10 ) return false ;
49+ if (date[4 ] != ' -' || date[7 ] != ' -' ) return false ;
50+
51+ for (int i = 0 ; i < 10 ; ++i) {
52+ if (i == 4 || i == 7 ) continue ;
53+ if (!std::isdigit (date[i])) return false ;
2454 }
25- return *this ;
55+
56+ int year = std::atoi (date.substr (0 , 4 ).c_str ());
57+ int month = std::atoi (date.substr (5 , 2 ).c_str ());
58+ int day = std::atoi (date.substr (8 , 2 ).c_str ());
59+
60+ if (year < 2009 || month < 1 || month > 12 || day < 1 || day > 31 ) {
61+ return false ;
62+ }
63+
64+ return true ;
2665}
2766
28- void BitcoinExchange::parseLine (const std::string &line) {
29- std::istringstream stream (line);
30- std::string date, valueStr;
31- if (std::getline (stream, date, ' ,' ) && std::getline (stream, valueStr)) {
32- float value = std::stof (valueStr);
33- validateDate (date);
34- validateValue (value);
35- addValue (date, value);
67+ bool BitcoinExchange::_isValidValue (const std::string& valueStr, float & value) {
68+ char * end;
69+ value = std::strtof (valueStr.c_str (), &end);
70+
71+ while (*end != ' \0 ' && std::isspace (*end)) {
72+ end++;
73+ }
74+ if (*end != ' \0 ' ) return false ; // Check if the entire string was consumed
75+
76+ if (value < 0 ) {
77+ std::cout << " Error: not a positive number." << std::endl;
78+ return false ;
3679 }
80+ if (value > 1000 ) {
81+ std::cout << " Error: too large a number." << std::endl;
82+ return false ;
83+ }
84+ return true ;
3785}
3886
39- /* *
40- * @brief When loading data from the data.csv file, we need to do ',' splitting.
41- * This is not the same as the splitting in the input.txt file, which uses '|' as a separator.
42- *
43- * @param filename
44- * @param splitChars
45- */
46- void BitcoinExchange::loadData (const std::string &filename, const std::string &splitChars) {
47- std::ifstream file (filename);
87+ void BitcoinExchange::processInputFile (const std::string& inputPath) {
88+ std::ifstream inputFile (inputPath.c_str ());
89+ if (!inputFile.is_open ()) {
90+ std::cout << " Error: could not open file." << std::endl;
91+ return ;
92+ }
93+
4894 std::string line;
95+ std::getline (inputFile, line);
4996
50- if (!file.is_open ()) {
51- throw std::runtime_error (" Could not open file: " + filename);
97+ if (line != " date | value" ) {
98+ std::cout << " Error: bad input => " << line << std::endl;
99+ return ;
52100 }
53101
54- // check the first line (either "date, value" or "date | value")
55- if (std::getline (file, line)) {
56- if (line.find (' ,' ) != std::string::npos) {
57- // If the line contains a comma, we assume it's a CSV format
58- while (std::getline (file, line)) {
59- parseLine (line);
60- }
61- } else if (line.find (' |' ) != std::string::npos) {
62- // If the line contains a pipe, we assume it's a different format
63- while (std::getline (file, line)) {
64- std::replace (line.begin (), line.end (), ' |' , ' ,' );
65- parseLine (line);
102+ while (std::getline (inputFile, line)) {
103+ std::stringstream ss (line);
104+ std::string date;
105+ std::string separator;
106+ std::string valueStr;
107+
108+ ss >> date >> separator >> valueStr;
109+
110+ if (date.empty () || separator != " |" || valueStr.empty ()) {
111+ std::cout << " Error: bad input => " << line << std::endl;
112+ continue ;
113+ }
114+
115+ float value;
116+ if (!_isValidDate (date)) {
117+ std::cout << " Error: bad input => " << date << std::endl;
118+ continue ;
119+ }
120+ if (!_isValidValue (valueStr, value)) {
121+ continue ;
122+ }
123+
124+ // Find the exchange rate
125+ std::map<std::string, float >::iterator it = _data.lower_bound (date);
126+
127+ if (it == _data.end () || it->first != date) {
128+ if (it == _data.begin ()) {
129+ std::cout << " Error: no data available for or before " << date << std::endl;
130+ continue ;
66131 }
67- } else {
68- throw std::runtime_error (" Unknown file format in: " + filename);
132+ --it; // Decrement to get the closest earlier date
69133 }
134+
135+ float exchangeRate = it->second ;
136+ std::cout << date << " => " << value << " = " << value * exchangeRate << std::endl;
70137 }
71138}
0 commit comments