#include "breeze/Text.hpp" #include #include namespace breeze::text { std::string trim(std::string_view s) { std::size_t b = 0; std::size_t e = s.size(); while (b < e && std::isspace(static_cast(s[b]))) ++b; while (e > b && std::isspace(static_cast(s[e - 1]))) --e; return std::string(s.substr(b, e - b)); } std::vector split(std::string_view s, char delimiter) { std::vector out; std::size_t start = 0; while (true) { std::size_t pos = s.find(delimiter, start); if (pos == std::string_view::npos) { out.emplace_back(s.substr(start)); return out; } out.emplace_back(s.substr(start, pos - start)); start = pos + 1; } } std::vector splitLines(std::string_view s) { std::vector lines = split(s, '\n'); for (std::string& line : lines) { if (!line.empty() && line.back() == '\r') line.pop_back(); } if (!lines.empty() && lines.back().empty()) lines.pop_back(); return lines; } std::string join(const std::vector& parts, std::string_view separator) { std::string out; for (std::size_t i = 0; i < parts.size(); ++i) { if (i != 0) out += separator; out += parts[i]; } return out; } std::string lower(std::string_view s) { std::string out(s); std::transform(out.begin(), out.end(), out.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return out; } bool startsWith(std::string_view s, std::string_view prefix) { return s.size() >= prefix.size() && s.substr(0, prefix.size()) == prefix; } bool endsWith(std::string_view s, std::string_view suffix) { return s.size() >= suffix.size() && s.substr(s.size() - suffix.size()) == suffix; } std::string replaceAll(std::string s, std::string_view from, std::string_view to) { if (from.empty()) return s; std::size_t pos = 0; while ((pos = s.find(from, pos)) != std::string::npos) { s.replace(pos, from.size(), to); pos += to.size(); } return s; } std::string snakeCase(std::string_view s) { std::string out; for (std::size_t i = 0; i < s.size(); ++i) { unsigned char c = static_cast(s[i]); if (c == '-' || c == ' ' || c == '.') c = '_'; if (std::isupper(c)) { bool prevLowerOrDigit = i > 0 && (std::islower(static_cast(s[i - 1])) || std::isdigit(static_cast(s[i - 1]))); bool acronymEnds = i > 0 && std::isupper(static_cast(s[i - 1])) && i + 1 < s.size() && std::islower(static_cast(s[i + 1])); if ((prevLowerOrDigit || acronymEnds) && !out.empty() && out.back() != '_') out += '_'; out += static_cast(std::tolower(c)); } else { if (c == '_' && (out.empty() || out.back() == '_')) continue; out += static_cast(c); } } while (!out.empty() && out.back() == '_') out.pop_back(); return out; } std::string normalized(std::string_view s) { std::string out; for (char c : s) { unsigned char u = static_cast(c); if (std::isalnum(u)) out += static_cast(std::tolower(u)); } return out; } bool isName(std::string_view s, bool allowDash) { if (s.empty() || !std::isalpha(static_cast(s[0]))) return false; return std::all_of(s.begin(), s.end(), [allowDash](char c) { unsigned char u = static_cast(c); return std::isalnum(u) || c == '_' || (allowDash && c == '-'); }); } bool isTargetId(std::string_view s) { if (s.empty() || !(std::isalpha(static_cast(s[0])) || s[0] == '_')) return false; return std::all_of(s.begin(), s.end(), [](char c) { unsigned char u = static_cast(c); return std::isalnum(u) || c == '_' || c == '.' || c == '+' || c == '-' || c == ':'; }); } std::string orNone(std::string_view s) { return s.empty() ? std::string("") : std::string(s); } }