CPP09 1.0
読み取り中…
検索中…
一致する文字列を見つけられません
BitcoinExchange.cpp
[詳解]
1/* ************************************************************************** */
2/* */
3/* ::: :::::::: */
4/* BitcoinExchange.cpp :+: :+: :+: */
5/* +:+ +:+ +:+ */
6/* By: kamitsui <kamitsui@student.42tokyo.jp> +#+ +:+ +#+ */
7/* +#+#+#+#+#+ +#+ */
8/* Created: 2025/08/28 19:19:55 by kamitsui #+# #+# */
9/* Updated: 2025/08/28 19:19:57 by kamitsui ### ########.fr */
10/* */
11/* ************************************************************************** */
12
17#include "BitcoinExchange.hpp"
18
19// --- Orthodox Canonical Form ---
20
22
24
25// コピーコンストラクタ(実装は不要)
27
28// 代入演算子(実装は不要)
29BitcoinExchange &BitcoinExchange::operator=(const BitcoinExchange &rhs) {
30 (void)rhs;
31 return *this;
32}
33
34// --- Private Helper Methods Implementation ---
35
36// 文字列の先頭と末尾の空白を削除するヘルパー関数
37std::string BitcoinExchange::trim(const std::string &str) const {
38 const std::string whitespace = " \t";
39 const size_t strBegin = str.find_first_not_of(whitespace);
40 if (strBegin == std::string::npos)
41 return ""; // 空白のみの文字列
42
43 const size_t strEnd = str.find_last_not_of(whitespace);
44 const size_t strRange = strEnd - strBegin + 1;
45
46 return str.substr(strBegin, strRange);
47}
48
49// 日付の妥当性を検証するヘルパー関数
50bool BitcoinExchange::isValidDate(const std::string &dateStr) const {
51 if (dateStr.length() != 10 || dateStr[4] != '-' || dateStr[7] != '-') {
52 return false;
53 }
54
55 std::string yearStr = dateStr.substr(0, 4);
56 std::string monthStr = dateStr.substr(5, 2);
57 std::string dayStr = dateStr.substr(8, 2);
58
59 for (size_t i = 0; i < yearStr.length(); ++i)
60 if (!isdigit(yearStr[i]))
61 return false;
62 for (size_t i = 0; i < monthStr.length(); ++i)
63 if (!isdigit(monthStr[i]))
64 return false;
65 for (size_t i = 0; i < dayStr.length(); ++i)
66 if (!isdigit(dayStr[i]))
67 return false;
68
69 int year = std::atoi(yearStr.c_str());
70 int month = std::atoi(monthStr.c_str());
71 int day = std::atoi(dayStr.c_str());
72
73 if (month < 1 || month > 12 || day < 1 || day > 31) {
74 return false;
75 }
76
77 // 各月の日数のチェック
78 int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
79 // うるう年のチェック
80 if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
81 daysInMonth[2] = 29;
82 }
83
84 if (day > daysInMonth[month]) {
85 return false;
86 }
87
88 return true;
89}
90
91// 値の妥当性を検証するヘルパー関数
92bool BitcoinExchange::isValidValue(const std::string &valueStr, double &value) const {
93 char *end;
94 value = std::strtod(valueStr.c_str(), &end);
95
96 // 変換できなかった、または余分な文字がある場合
97 if (*end != '\0') {
98 return false;
99 }
100 if (value < 0) {
101 std::cerr << "Error: not a positive number." << std::endl;
102 return false;
103 }
104 if (value > 1000) {
105 std::cerr << "Error: too large a number." << std::endl;
106 return false;
107 }
108 return true;
109}
110
111// --- Public Methods Implementation ---
112
113// データベースファイルを読み込む
115 std::ifstream dbFile(filename.c_str());
116 if (!dbFile.is_open()) {
117 throw std::runtime_error("could not open database file.");
118 }
119
120 std::string line;
121 // ヘッダー行をスキップ
122 std::getline(dbFile, line);
123
124 while (std::getline(dbFile, line)) {
125 std::stringstream ss(line);
126 std::string date;
127 std::string rateStr;
128 double rate;
129
130 if (std::getline(ss, date, ',') && std::getline(ss, rateStr)) {
131 char *end;
132 rate = std::strtod(rateStr.c_str(), &end);
133 if (*end == '\0') { // 変換成功
134 _exchangeRates[date] = rate;
135 }
136 }
137 }
138}
139
140// 入力ファイルを処理する
142 std::ifstream inputFile(filename.c_str());
143 if (!inputFile.is_open()) {
144 throw std::runtime_error("could not open input file.");
145 }
146
147 std::string line;
148 // ヘッダー行をスキップ
149 std::getline(inputFile, line);
150
151 while (std::getline(inputFile, line)) {
152 std::stringstream ss(line);
153 std::string dateStr;
154 std::string valueStr;
155 std::string separator;
156
157 // " | " で分割を試みる
158 size_t pos = line.find(" | ");
159 if (pos == std::string::npos) {
160 std::cerr << "Error: bad input => " << line << std::endl;
161 continue;
162 }
163
164 dateStr = trim(line.substr(0, pos));
165 valueStr = trim(line.substr(pos + 3));
166
167 if (!isValidDate(dateStr)) {
168 std::cerr << "Error: bad input => " << line << std::endl;
169 continue;
170 }
171
172 double value;
173 if (!isValidValue(valueStr, value)) {
174 // isValidValue内でエラーメッセージが出力される
175 continue;
176 }
177
178 // lower_boundを使用して、指定された日付以上の最初の要素を見つける
180
181 // もしitが指す日付が入力日付より後、またはmapの終端なら、1つ前の要素を使う
182 if (it == _exchangeRates.end() || it->first != dateStr) {
183 if (it == _exchangeRates.begin()) {
184 std::cerr << "Error: no data available for or before date " << dateStr << std::endl;
185 continue;
186 }
187 --it; // 1つ前の(より小さい)日付に移動
188 }
189
190 double exchangeRate = it->second;
191 std::cout << dateStr << " => " << value << " = " << (value * exchangeRate) << std::endl;
192 }
193}
ビットコインの価格情報に基づき価値を計算するBitcoinExchangeクラスを提供します。
T atoi(T... args)
T begin(T... args)
T c_str(T... args)
ビットコインの価格データベースを管理し、入力ファイルに基づいて価値を計算するクラス。
void processInputFile(const std::string &filename)
指定された入力ファイルを処理し、各行のビットコインの価値を計算して出力します。
BitcoinExchange()
デフォルトコンストラクタ。
void loadDatabase(const std::string &filename)
CSV形式のデータベースファイルを読み込み、為替レートを内部マップに格納します。
~BitcoinExchange()
デストラクタ。
T end(T... args)
T endl(T... args)
T find_first_not_of(T... args)
T find(T... args)
T find_last_not_of(T... args)
T getline(T... args)
T is_open(T... args)
T lower_bound(T... args)
T length(T... args)
T strtod(T... args)
T substr(T... args)