string_utils.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #include "common/string_utils.hpp"
  2. #include <cstdlib>
  3. #include <openssl/bio.h>
  4. #include <openssl/evp.h>
  5. #include <openssl/buffer.h>
  6. namespace smartbotic::common {
  7. std::string StringUtils::trim(std::string_view str) {
  8. return trimRight(trimLeft(str));
  9. }
  10. std::string StringUtils::trimLeft(std::string_view str) {
  11. auto it = std::find_if(str.begin(), str.end(),
  12. [](unsigned char c) { return !std::isspace(c); });
  13. return std::string(it, str.end());
  14. }
  15. std::string StringUtils::trimRight(std::string_view str) {
  16. auto it = std::find_if(str.rbegin(), str.rend(),
  17. [](unsigned char c) { return !std::isspace(c); });
  18. return std::string(str.begin(), it.base());
  19. }
  20. std::string StringUtils::toLower(std::string_view str) {
  21. std::string result(str);
  22. std::transform(result.begin(), result.end(), result.begin(),
  23. [](unsigned char c) { return std::tolower(c); });
  24. return result;
  25. }
  26. std::string StringUtils::toUpper(std::string_view str) {
  27. std::string result(str);
  28. std::transform(result.begin(), result.end(), result.begin(),
  29. [](unsigned char c) { return std::toupper(c); });
  30. return result;
  31. }
  32. std::vector<std::string> StringUtils::split(std::string_view str, char delimiter) {
  33. std::vector<std::string> result;
  34. std::string current;
  35. for (char c : str) {
  36. if (c == delimiter) {
  37. result.push_back(std::move(current));
  38. current.clear();
  39. } else {
  40. current += c;
  41. }
  42. }
  43. result.push_back(std::move(current));
  44. return result;
  45. }
  46. std::vector<std::string> StringUtils::split(std::string_view str, std::string_view delimiter) {
  47. std::vector<std::string> result;
  48. size_t start = 0;
  49. size_t end = str.find(delimiter);
  50. while (end != std::string_view::npos) {
  51. result.emplace_back(str.substr(start, end - start));
  52. start = end + delimiter.length();
  53. end = str.find(delimiter, start);
  54. }
  55. result.emplace_back(str.substr(start));
  56. return result;
  57. }
  58. std::string StringUtils::join(const std::vector<std::string>& parts, std::string_view delimiter) {
  59. if (parts.empty()) return "";
  60. std::ostringstream ss;
  61. ss << parts[0];
  62. for (size_t i = 1; i < parts.size(); ++i) {
  63. ss << delimiter << parts[i];
  64. }
  65. return ss.str();
  66. }
  67. bool StringUtils::startsWith(std::string_view str, std::string_view prefix) {
  68. return str.size() >= prefix.size() && str.substr(0, prefix.size()) == prefix;
  69. }
  70. bool StringUtils::endsWith(std::string_view str, std::string_view suffix) {
  71. return str.size() >= suffix.size() &&
  72. str.substr(str.size() - suffix.size()) == suffix;
  73. }
  74. bool StringUtils::contains(std::string_view str, std::string_view substr) {
  75. return str.find(substr) != std::string_view::npos;
  76. }
  77. std::string StringUtils::replace(std::string_view str, std::string_view from, std::string_view to) {
  78. std::string result(str);
  79. size_t pos = result.find(from);
  80. if (pos != std::string::npos) {
  81. result.replace(pos, from.length(), to);
  82. }
  83. return result;
  84. }
  85. std::string StringUtils::replaceAll(std::string_view str, std::string_view from, std::string_view to) {
  86. std::string result(str);
  87. size_t pos = 0;
  88. while ((pos = result.find(from, pos)) != std::string::npos) {
  89. result.replace(pos, from.length(), to);
  90. pos += to.length();
  91. }
  92. return result;
  93. }
  94. std::string StringUtils::interpolate(std::string_view tmpl,
  95. const std::unordered_map<std::string, std::string>& vars) {
  96. std::string result(tmpl);
  97. std::regex pattern(R"(\$\{([^}]+)\})");
  98. std::string output;
  99. auto it = std::sregex_iterator(result.begin(), result.end(), pattern);
  100. auto end = std::sregex_iterator();
  101. size_t lastPos = 0;
  102. for (; it != end; ++it) {
  103. output += result.substr(lastPos, it->position() - lastPos);
  104. std::string varName = (*it)[1].str();
  105. auto found = vars.find(varName);
  106. if (found != vars.end()) {
  107. output += found->second;
  108. } else {
  109. output += it->str(); // Keep original if not found
  110. }
  111. lastPos = it->position() + it->length();
  112. }
  113. output += result.substr(lastPos);
  114. return output;
  115. }
  116. std::string StringUtils::expandEnvVars(std::string_view str) {
  117. std::string result(str);
  118. std::regex pattern(R"(\$\{([^:}]+)(?::([^}]*))?\})");
  119. std::string output;
  120. auto it = std::sregex_iterator(result.begin(), result.end(), pattern);
  121. auto end = std::sregex_iterator();
  122. size_t lastPos = 0;
  123. for (; it != end; ++it) {
  124. output += result.substr(lastPos, it->position() - lastPos);
  125. std::string varName = (*it)[1].str();
  126. std::string defaultValue = (*it)[2].matched ? (*it)[2].str() : "";
  127. const char* envValue = std::getenv(varName.c_str());
  128. if (envValue) {
  129. output += envValue;
  130. } else {
  131. output += defaultValue;
  132. }
  133. lastPos = it->position() + it->length();
  134. }
  135. output += result.substr(lastPos);
  136. return output;
  137. }
  138. std::string StringUtils::urlEncode(std::string_view str) {
  139. std::ostringstream escaped;
  140. escaped.fill('0');
  141. escaped << std::hex;
  142. for (char c : str) {
  143. if (std::isalnum(static_cast<unsigned char>(c)) ||
  144. c == '-' || c == '_' || c == '.' || c == '~') {
  145. escaped << c;
  146. } else {
  147. escaped << std::uppercase;
  148. escaped << '%' << std::setw(2) << int(static_cast<unsigned char>(c));
  149. escaped << std::nouppercase;
  150. }
  151. }
  152. return escaped.str();
  153. }
  154. std::string StringUtils::urlDecode(std::string_view str) {
  155. std::string result;
  156. result.reserve(str.size());
  157. for (size_t i = 0; i < str.size(); ++i) {
  158. if (str[i] == '%' && i + 2 < str.size()) {
  159. int hex = std::stoi(std::string(str.substr(i + 1, 2)), nullptr, 16);
  160. result += static_cast<char>(hex);
  161. i += 2;
  162. } else if (str[i] == '+') {
  163. result += ' ';
  164. } else {
  165. result += str[i];
  166. }
  167. }
  168. return result;
  169. }
  170. std::string StringUtils::base64Encode(std::string_view data) {
  171. BIO* b64 = BIO_new(BIO_f_base64());
  172. BIO* bio = BIO_new(BIO_s_mem());
  173. bio = BIO_push(b64, bio);
  174. BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
  175. BIO_write(bio, data.data(), static_cast<int>(data.size()));
  176. BIO_flush(bio);
  177. BUF_MEM* bufferPtr;
  178. BIO_get_mem_ptr(bio, &bufferPtr);
  179. std::string result(bufferPtr->data, bufferPtr->length);
  180. BIO_free_all(bio);
  181. return result;
  182. }
  183. std::string StringUtils::base64Decode(std::string_view encoded) {
  184. BIO* b64 = BIO_new(BIO_f_base64());
  185. BIO* bio = BIO_new_mem_buf(encoded.data(), static_cast<int>(encoded.size()));
  186. bio = BIO_push(b64, bio);
  187. BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
  188. std::string result(encoded.size(), '\0');
  189. int length = BIO_read(bio, result.data(), static_cast<int>(result.size()));
  190. BIO_free_all(bio);
  191. if (length > 0) {
  192. result.resize(length);
  193. } else {
  194. result.clear();
  195. }
  196. return result;
  197. }
  198. std::string StringUtils::hexEncode(const std::vector<uint8_t>& data) {
  199. static const char hex[] = "0123456789abcdef";
  200. std::string result;
  201. result.reserve(data.size() * 2);
  202. for (uint8_t byte : data) {
  203. result += hex[byte >> 4];
  204. result += hex[byte & 0x0f];
  205. }
  206. return result;
  207. }
  208. std::vector<uint8_t> StringUtils::hexDecode(std::string_view hex) {
  209. std::vector<uint8_t> result;
  210. result.reserve(hex.size() / 2);
  211. for (size_t i = 0; i + 1 < hex.size(); i += 2) {
  212. uint8_t byte = static_cast<uint8_t>(std::stoi(std::string(hex.substr(i, 2)), nullptr, 16));
  213. result.push_back(byte);
  214. }
  215. return result;
  216. }
  217. } // namespace smartbotic::common