Files
BreezeCLI/source/BreezeCore/src/Text.cpp
T
2026-10-24 09:53:48 -03:00

169 lines
4.0 KiB
C++

#include "breeze/Text.hpp"
#include <cctype>
#include <algorithm>
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<unsigned char>(s[b])))
++b;
while (e > b && std::isspace(static_cast<unsigned char>(s[e - 1])))
--e;
return std::string(s.substr(b, e - b));
}
std::vector<std::string> split(std::string_view s, char delimiter)
{
std::vector<std::string> 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<std::string> splitLines(std::string_view s)
{
std::vector<std::string> 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<std::string>& 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<char>(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<unsigned char>(s[i]);
if (c == '-' || c == ' ' || c == '.')
c = '_';
if (std::isupper(c))
{
bool prevLowerOrDigit =
i > 0 && (std::islower(static_cast<unsigned char>(s[i - 1])) ||
std::isdigit(static_cast<unsigned char>(s[i - 1])));
bool acronymEnds = i > 0 && std::isupper(static_cast<unsigned char>(s[i - 1])) &&
i + 1 < s.size() &&
std::islower(static_cast<unsigned char>(s[i + 1]));
if ((prevLowerOrDigit || acronymEnds) && !out.empty() && out.back() != '_')
out += '_';
out += static_cast<char>(std::tolower(c));
}
else
{
if (c == '_' && (out.empty() || out.back() == '_'))
continue;
out += static_cast<char>(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<unsigned char>(c);
if (std::isalnum(u))
out += static_cast<char>(std::tolower(u));
}
return out;
}
bool isName(std::string_view s, bool allowDash)
{
if (s.empty() || !std::isalpha(static_cast<unsigned char>(s[0])))
return false;
return std::all_of(s.begin(), s.end(),
[allowDash](char c)
{
unsigned char u = static_cast<unsigned char>(c);
return std::isalnum(u) || c == '_' || (allowDash && c == '-');
});
}
bool isTargetId(std::string_view s)
{
if (s.empty() || !(std::isalpha(static_cast<unsigned char>(s[0])) || s[0] == '_'))
return false;
return std::all_of(s.begin(), s.end(),
[](char c)
{
unsigned char u = static_cast<unsigned char>(c);
return std::isalnum(u) || c == '_' || c == '.' || c == '+' ||
c == '-' || c == ':';
});
}
std::string orNone(std::string_view s)
{
return s.empty() ? std::string("<none>") : std::string(s);
}
}