Created
May 15, 2026 06:43
-
-
Save GasparVardanyan/e263b5ddaed89419949a5de1e0c7dc24 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <cctype> | |
| #include <ctime> | |
| #include <stdexcept> | |
| #include <vector> | |
| #include <string> | |
| std::vector<std::string> split(const std::string &s, char delimiter) { | |
| std::vector <std::string> tokens; | |
| # if 0 // stringstream is too much heavy for basic tokenization | |
| std::string token; | |
| std::stringstream ss (s); | |
| while (std::getline(ss, token, delimiter)) { | |
| tokens.push_back(token); | |
| } | |
| # else | |
| std::size_t tBegin = 0; | |
| std::size_t tEnd = 0; | |
| while (std::string::npos != (tEnd = s.find (delimiter, tBegin))) { | |
| tokens.push_back (s.substr (tBegin, tEnd - tBegin)); | |
| tBegin = tEnd + 1; | |
| } | |
| if (tBegin < s.size ()) { | |
| tokens.push_back (s.substr (tBegin, s.size ())); | |
| } | |
| # endif | |
| return tokens; | |
| } | |
| /* ------------------------------------------------------------ | |
| Trim whitespace from both ends | |
| ------------------------------------------------------------ */ | |
| std::string trim(const std::string &s) { | |
| if (s.empty()) return ""; | |
| std::size_t start = s.find_first_not_of(" \t\r\n"); | |
| if (start == std::string::npos) return ""; | |
| std::size_t end = s.find_last_not_of(" \t\r\n"); | |
| return s.substr(start, end - start + 1); | |
| } | |
| /* ------------------------------------------------------------ | |
| C++98-safe integer conversion (replaces stoi) | |
| It's not C++98 safe. C++98 uses C90's atoi implementation and | |
| the C90 standard says: | |
| int atoi(const char *nptr); | |
| The atoi function converts the initial portion of the string | |
| pointed to by nptr to int representation. Except for the behavior | |
| on error, it is equivalent to | |
| (int)strtol(nptr, (char **)NULL, 10) | |
| So in case of error the behaviour is undefined! | |
| Btw this project doesn't compile with C++98. At least C++11 is necessary. | |
| ------------------------------------------------------------ */ | |
| // NOTE: better to use std::string_view , but since commets talk about C++98 | |
| // safety and C++11 is the oldest C++ standard after C++98 where this project | |
| // compiles, I avoid std::string_view which is introduced in C++17 | |
| int toInt(const std::string &s) { | |
| # if 0 | |
| return atoi(s.c_str()); | |
| # endif | |
| try { | |
| return std::stoi (s); | |
| } | |
| catch (...) { | |
| // Can throw: | |
| // - std::invalid_argument if no conversion could be performed. | |
| // | |
| // - std::out_of_range if the converted value would fall out of the range | |
| // of the result type or if the underlying function (std::strtol or | |
| // std::strtoll) sets errno to ERANGE. | |
| return 0; | |
| } | |
| } | |
| /* ------------------------------------------------------------ | |
| C++98-safe double conversion (replaces stod) | |
| Not safe. See toInt. | |
| ------------------------------------------------------------ */ | |
| double toDouble(const std::string &s) { | |
| try { | |
| return std::stod (s); | |
| } | |
| catch (...) { | |
| return 0; | |
| } | |
| } | |
| /* ------------------------------------------------------------ | |
| Validate time format HH:MM or --:-- | |
| ------------------------------------------------------------ */ | |
| bool isValidTime(const std::string &t) { | |
| if (t == "--:--") return true; | |
| if (t.size() != 5) return false; | |
| if (t[2] != ':') return false; | |
| if (!std::isdigit(t[0]) || !std::isdigit(t[1])) return false; | |
| if (!std::isdigit(t[3]) || !std::isdigit(t[4])) return false; | |
| int H = (t[0] - '0') * 10 + (t[1] - '0'); | |
| int M = (t[3] - '0') * 10 + (t[4] - '0'); | |
| // H and M can't be negative | |
| // if (H < 0 || H > 23) return false; | |
| // if (M < 0 || M > 59) return false; | |
| if (H > 23 || M > 59) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| int toMinutes(const std::string &t) { | |
| if (t == "--:--") return 0; | |
| int H = (t[0] - '0') * 10 + (t[1] - '0'); | |
| int M = (t[3] - '0') * 10 + (t[4] - '0'); | |
| return H * 60 + M; | |
| } | |
| bool dateSortAscending(const std::string &a, const std::string &b) { | |
| // TODO: review | |
| // If we aren't limited with C++11, std::string_view is a better choice here | |
| // (after reimplementing toInt to work with string views) | |
| int d1 = toInt(a.substr(0, 2)); | |
| int m1 = toInt(a.substr(3, 2)); | |
| int y1 = toInt(a.substr(6, 4)); | |
| int d2 = toInt(b.substr(0, 2)); | |
| int m2 = toInt(b.substr(3, 2)); | |
| int y2 = toInt(b.substr(6, 4)); | |
| if (y1 != y2) return y1 < y2; | |
| if (m1 != m2) return m1 < m2; | |
| return d1 < d2; | |
| } | |
| bool isValidWeekday (const std::string &date) { | |
| // date format: DD-MM-YYYY | |
| if (date.length () != 10) { | |
| // TODO: what must be returned in invalid date case? | |
| throw std::runtime_error ("invalid date"); | |
| } | |
| int d = toInt(date.substr(0,2)); | |
| int m = toInt(date.substr(3,2)); | |
| int y = toInt(date.substr(6,4)); | |
| if (false == ( | |
| 1 <= d && d <= 30 && | |
| 1 <= m && m <= 12 && | |
| 1 <= y && y <= 9999 // preserving 0 as an toInt error | |
| )) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| int getWeekday(const std::string &date) { | |
| // date format: DD-MM-YYYY | |
| if (false == isValidWeekday (date)) { // TODO: is this the desired behaviour? | |
| return 0; // return sunday | |
| } | |
| int d = toInt(date.substr(0,2)); | |
| int m = toInt(date.substr(3,2)); | |
| int y = toInt(date.substr(6,4)); | |
| if (false == ( | |
| 1 <= d && d <= 30 && | |
| 1 <= m && m <= 12 && | |
| 1 <= y && y <= 9999 | |
| )) { | |
| return -1; | |
| } | |
| tm t = { 0 }; | |
| // std::memset(&t, 0, sizeof(t)); // no need for memset, structs can be initialized with zeros | |
| t.tm_mday = d; | |
| t.tm_mon = m - 1; | |
| t.tm_year = y - 1900; | |
| std::mktime (&t); // normalizes and fills tm_wday | |
| return t.tm_wday; // 0 = Sunday | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment