string_utils.cpp 8.2 KB

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