#include "String.hpp" #include #include #include #include #include namespace ostd { String String::Tokens::next(void) { if (!hasNext()) return ""; //TODO: Error return m_tokens[m_current_index++]; } String String::Tokens::previous(void) { if (!hasPrevious()) return ""; //TODO: Error return m_tokens[--m_current_index]; } String& String::ltrim(void) { m_data.erase(m_data.begin(), std::find_if(m_data.begin(), m_data.end(), [](unsigned char ch) { return !std::isspace(ch); })); return *this; } String& String::rtrim(void) { m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), m_data.end()); return *this; } String& String::trim(void) { return ltrim().rtrim(); } String& String::toLower(void) { std::transform(m_data.begin(), m_data.end(), m_data.begin(), [](unsigned char c){ return std::tolower(c); }); return *this; } String& String::toUpper(void) { std::transform(m_data.begin(), m_data.end(), m_data.begin(), [](unsigned char c){ return std::toupper(c); }); return *this; } String& String::addPadding(uint32_t new_string_length, char c, ePaddingBehavior padding_behavior) { if (len() - 1 >= new_string_length) return *this; uint32_t diff = new_string_length - len(); int32_t leftPadding = 0; int32_t rightPadding = 0; switch (padding_behavior) { case ePaddingBehavior::ForceEvenNegative: if (diff % 2 != 0) diff--; leftPadding = rightPadding = (diff / 2); break; case ePaddingBehavior::ForceEvenPositive: if (diff % 2 != 0) diff++; leftPadding = rightPadding = (diff / 2); break; case ePaddingBehavior::AllowOddExtraLeft: if (diff % 2 != 0) { diff--; leftPadding = rightPadding = (diff / 2); leftPadding++; } else leftPadding = rightPadding = (diff / 2); break; case ePaddingBehavior::AllowOddExtraRight: if (diff % 2 != 0) { diff--; leftPadding = rightPadding = (diff / 2); rightPadding++; } else leftPadding = rightPadding = (diff / 2); break; } if (leftPadding < 0 || rightPadding < 0) return *this; return addLeftPadding(len() + leftPadding, c).addRightPadding(len() + rightPadding, c); } String& String::addLeftPadding(uint32_t new_string_length, char c) { reverse(); while (len() < new_string_length) m_data += c; reverse(); return *this; } String& String::addRightPadding(uint32_t new_string_length, char c) { while (len() < new_string_length) m_data += c; return *this; } String& String::reverse(void) { std::reverse(m_data.begin(), m_data.end()); return *this; } String& String::replaceAll(const String& what, const String& with) { while (contains(what)) replaceFirst(what, with); return *this; } String& String::replaceFirst(const String& what, const String& with) { int32_t index = indexOf(what); if (index == -1) return *this; m_data.replace(index, what.len(), with.cpp_str()); return *this; } String& String::regexReplace(const String& regex_pattern, const String& replace_with, bool case_insensitive) { try { boost::regex rgx(regex_pattern.cpp_str(), (case_insensitive ? boost::regex_constants::icase : boost::regex_constants::normal)); m_data = boost::regex_replace(m_data, rgx, replace_with.cpp_str()); return *this; } catch(const boost::regex_error& err) { std::cerr << err.what() << '\n'; //TODO: Better error handling return *this; } return *this; } String& String::put(uint32_t index, char c) { if (index < m_data.length()) m_data[index] = c; return *this; } String& String::substr(uint32_t start, int32_t end) { if (end < 0) m_data = m_data.substr(start); else m_data = m_data.substr(start, end - start); return *this; } String& String::fixedLength(uint32_t length, char fill_character, const String& truncate_indicator) { if (length < truncate_indicator.len()) return *this; if (len() > length) { int32_t tr_len = truncate_indicator.len(); substr(0, length - tr_len); return add(truncate_indicator); } else if (len() < length) return addRightPadding(length, fill_character); return *this; } String& String::addChar(char c) { m_data += c; return *this; } String& String::add(const String& se) { m_data += se.cpp_str(); return *this; } String& String::add(uint8_t i) { m_data += std::to_string(i); return *this; } String& String::add(int8_t i) { m_data += std::to_string(i); return *this; } String& String::add(uint16_t i) { m_data += std::to_string(i); return *this; } String& String::add(int16_t i) { m_data += std::to_string(i); return *this; } String& String::add(uint32_t i) { m_data += std::to_string(i); return *this; } String& String::add(int32_t i) { m_data += std::to_string(i); return *this; } String& String::add(uint64_t i) { m_data += std::to_string(i); return *this; } String& String::add(int64_t i) { m_data += std::to_string(i); return *this; } String& String::add(float f, uint8_t precision) { std::stringstream stream; if (precision != 0) stream << std::fixed << std::setprecision(precision) << f; else stream << f; cpp_string s = stream.str(); return add(s); } String& String::add(double f, uint8_t precision) { std::stringstream stream; if (precision != 0) stream << std::fixed << std::setprecision(precision) << f; else stream << f; cpp_string s = stream.str(); return add(s); } //New String String String::new_ltrim(void) const { String __str = m_data; return __str.ltrim(); } String String::new_rtrim(void) const { String __str = m_data; return __str.rtrim(); } String String::new_trim(void) const { String __str = m_data; return __str.trim(); } String String::new_toLower(void) const { String __str = m_data; return __str.toLower(); } String String::new_toUpper(void) const { String __str = m_data; return __str.toUpper(); } String String::new_addPadding(uint32_t new_string_length, char c, ePaddingBehavior padding_behavior) const { String __str = m_data; return __str.addPadding(new_string_length, c, padding_behavior); } String String::new_addLeftPadding(uint32_t new_string_length, char c) const { String __str = m_data; return __str.addLeftPadding(new_string_length, c); } String String::new_addRightPadding(uint32_t new_string_length, char c) const { String __str = m_data; return __str.addRightPadding(new_string_length, c); } String String::new_reverse(void) const { String __str = m_data; return __str.reverse(); } String String::new_replaceAll(const String& what, const String& with) const { String __str = m_data; return __str.replaceAll(what, with); } String String::new_replaceFirst(const String& what, const String& with) const { String __str = m_data; return __str.replaceFirst(what, with); } String String::new_regexReplace(const String& regex_pattern, const String& replace_with, bool case_insensitive) const { String __str = m_data; return __str.regexReplace(regex_pattern, replace_with, case_insensitive); } String String::new_put(uint32_t index, char c) const { String __str = m_data; return __str.put(index, c); } String String::new_substr(uint32_t start, int32_t end) const { String __str = m_data; return __str.substr(start, end); } String String::new_fixedLength(uint32_t length, char fill_character, const String& truncate_indicator) const { String __str = m_data; return __str.fixedLength(length, fill_character, truncate_indicator); } String String::new_addChar(char c) const { String __str = m_data; return __str.addChar(c); } String String::new_add(const String& se) const { String __str = m_data; return __str.add(se); } String String::new_add(uint8_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(int8_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(uint16_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(int16_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(uint32_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(int32_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(uint64_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(int64_t i) const { String __str = m_data; return __str.add(i); } String String::new_add(float f, uint8_t precision) const { String __str = m_data; return __str.add(f, precision); } String String::new_add(double f, uint8_t precision) const { String __str = m_data; return __str.add(f, precision); } //Utility int64_t String::toInt(void) const { if (!isNumeric(false)) return 0; ostd::String str = String(m_data).trim().toLower(); if (!str.isInt()) return 0; int32_t base = 10; if (str.cpp_str().rfind("0x", 0) == 0) { str = str.substr(2); base = 16; } else if (str.cpp_str().rfind("0b", 0) == 0) { str = str.substr(2); base = 2; } return strtoul(str.c_str(), NULL, base); } float String::toFloat(void) const { if (!isNumeric(true)) return 0; return std::stof(m_data); } double String::toDouble(void) const { if (!isNumeric(true)) return 0; return std::stod(m_data); } bool String::isNumeric(bool decimal) const { if (decimal) { std::istringstream iss(m_data); double f; iss >> std::noskipws >> f; return iss.eof() && !iss.fail(); } return isInt(); } bool String::isInt(void) const { ostd::String str = String(m_data).trim().toLower(); bool isNumber = std::ranges::all_of(str.begin(), str.end(), [](char c){ return isdigit(c) != 0; }); return str.isHex() || str.isBin() || isNumber; } bool String::isHex(void) const { ostd::String hex = String(m_data).trim().toLower(); return hex.cpp_str().compare(0, 2, "0x") == 0 && hex.cpp_str().size() > 2 && hex.cpp_str().find_first_not_of("0123456789abcdef", 2) == std::string::npos; } bool String::isBin(void) const { ostd::String bin = String(m_data).trim().toLower(); return bin.cpp_str().compare(0, 2, "0b") == 0 && bin.cpp_str().size() > 2 && bin.cpp_str().find_first_not_of("01", 2) == std::string::npos; } bool String::contains(char c) const { return m_data.find(c) != std::string::npos; } bool String::contains(const String& str) const { return m_data.find(str.cpp_str()) != std::string::npos; } bool String::startsWith(const String& str) const { return m_data.starts_with(str); } bool String::endsWith(const String& str) const { return m_data.ends_with(str); } bool String::regexMatches(const String& regex_pattern, bool case_insensitive) const { try { boost::regex rgx(regex_pattern.cpp_str(), case_insensitive ? boost::regex_constants::icase : boost::regex_constants::normal); return boost::regex_search(m_data, rgx); } catch (const boost::regex_error& err) { std::cerr << err.what() << '\n'; //TODO: Better error handling return false; } } uint32_t String::count(const String& str) const { Tokens tok = tokenize(str, false, true); if (tok.count() < 1) return 0; return tok.count() - 1; } int32_t String::indexOf(char c, uint32_t start) const { cpp_string cc = ""; cc += c; int32_t pos = m_data.find(cc.c_str(), start); if (pos == std::string::npos) return -1; return pos; } int32_t String::indexOf(const String& str, uint32_t start) const { int32_t pos = m_data.find(str.c_str(), start); if (pos == std::string::npos) return -1; return pos; } int32_t String::lastIndexOf(char c) const { String se(m_data); se.reverse(); int32_t pos = se.indexOf(c); if (pos < 0) return -1; return len() - pos - 1; } int32_t String::lastIndexOf(const String& str) const { String se(m_data); se.reverse(); String se2(str); int32_t pos = se.indexOf(se2.new_reverse()); if (pos < 0) return -1; return len() - pos - str.len(); } String::Tokens String::tokenize(const String& delimiter, bool trim_tokens, bool allow_white_space_only_tokens) const { Tokens tokens; int32_t sindex = 0; int32_t eindex = 0; String __token = ""; while ((eindex = indexOf(delimiter, sindex)) != -1) { __token = new_substr(sindex, eindex); if (trim_tokens) { __token.trim(); if (__token != "") tokens.m_tokens.push_back(__token.cpp_str()); } else { if (allow_white_space_only_tokens && __token != "") tokens.m_tokens.push_back(__token.cpp_str()); else if (!allow_white_space_only_tokens && __token.new_trim() != "") tokens.m_tokens.push_back(__token.cpp_str()); } sindex = eindex + delimiter.len(); } __token = new_substr(sindex); if (trim_tokens) { __token.trim(); if (__token != "") tokens.m_tokens.push_back(__token.cpp_str()); } else { if (allow_white_space_only_tokens && __token != "") tokens.m_tokens.push_back(__token.cpp_str()); else if (!allow_white_space_only_tokens && __token.new_trim() != "") tokens.m_tokens.push_back(__token.cpp_str()); } return tokens; } String String::getHexStr(uint64_t value, bool prefix, uint8_t nbytes) { union { uint64_t val; uint8_t bytes[8]; } __tmp_editor; __tmp_editor.val = value; if (nbytes < 1 || nbytes > 8) nbytes = 1; std::ostringstream oss; if (prefix) oss << "0x"; for (int8_t b = nbytes - 1; b >= 0; b--) oss << std::setw(2) << std::setfill('0') << std::uppercase << std::hex << (int)__tmp_editor.bytes[b]; return oss.str(); } String String::getBinStr(uint64_t value, bool prefix, uint8_t nbytes) { union { uint64_t val; uint8_t bytes[8]; } __tmp_editor; __tmp_editor.val = value; if (nbytes < 1 || nbytes > 8) nbytes = 1; std::ostringstream oss; if (prefix) oss << "0b "; for (int8_t b = nbytes - 1; b >= 0; b--) oss << std::bitset<8>((char)__tmp_editor.bytes[b]) << " "; return oss.str(); } String String::duplicateChar(unsigned char c, uint16_t count) { String str = ""; for (uint16_t i = 0; i < count; i++) str = str += c; return str; } String operator+(const cpp_string& str1, const String& str) { return String(str1) + str; } std::ostream& operator<<(std::ostream& out, const String& val) { out << val.cpp_str(); return out; } }