LeviLamina
Loading...
Searching...
No Matches
StringUtils.h
1#pragma once
2
3#include <cerrno>
4#include <charconv>
5#include <cstddef>
6#include <cstdlib>
7#include <stdexcept>
8#include <string>
9#include <string_view>
10#include <type_traits>
11#include <utility>
12#include <vector>
13
14#include "ll/api/base/Concepts.h"
15#include "ll/api/base/Macro.h"
16#include "ll/api/base/StdInt.h"
17
18#include "ll/api/Expected.h"
19
20namespace ll::inline utils::string_utils {
21
22// "2021-03-24" -> ["2021", "03", "24"] (use '-' as split pattern)
23template <std::invocable<std::string_view> Fn>
24constexpr void splitByPattern(Fn&& fn, std::string_view s, std::string_view pattern, bool keepEmpty = false) {
25 if (s.empty()) return;
26 size_t pos{};
27 while ((pos = s.find(pattern)) != std::string::npos) {
28 if (keepEmpty || pos != 0) {
29 if (!std::invoke(std::forward<Fn>(fn), s.substr(0, pos))) return;
30 }
31 s = s.substr(pos + pattern.size());
32 }
33 if (keepEmpty || !s.empty()) std::invoke(std::forward<Fn>(fn), s);
34}
35template <concepts::IsString T>
36[[nodiscard]] constexpr decltype(auto) splitByPattern(T&& str, std::string_view pattern, bool keepEmpty = false) {
37 using ReturnTypeElement = std::conditional_t<std::is_same_v<T&&, std::string&&>, std::string, std::string_view>;
38 std::vector<ReturnTypeElement> ret;
39 splitByPattern(
40 [&](std::string_view sv) {
41 ret.push_back(ReturnTypeElement{sv});
42 return true;
43 },
44 str,
45 pattern,
46 keepEmpty
47 );
48 return ret;
49}
50
58constexpr std::string& replaceAll(std::string& str, std::string_view oldValue, std::string_view newValue) {
59 for (std::string::size_type pos(0); pos != std::string::npos; pos += newValue.length()) {
60 if ((pos = str.find(oldValue, pos)) != std::string::npos) str.replace(pos, oldValue.length(), newValue);
61 else break;
62 }
63 return str;
64}
65
66[[nodiscard]] constexpr std::string
67replaceAll(std::string const& str, std::string_view oldValue, std::string_view newValue) {
68 std::string ret = str;
69 replaceAll(ret, oldValue, newValue);
70 return ret;
71}
72
73constexpr bool
74replaceContent(std::string& str, std::string_view before, std::string_view after, std::string_view relplaceWith) {
75 auto startOffset = str.find(before);
76 if (startOffset == std::string::npos) return false;
77 startOffset += before.size();
78 auto endOffset = after.empty() ? std::string::npos : str.find(after, startOffset);
79 str.replace(startOffset, endOffset - startOffset, relplaceWith);
80 return true;
81}
82
83constexpr inline uchar digitFromByte[] = {
84 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
85 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
86 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10,
87 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
88 33, 34, 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
89 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255,
90 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
91 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
92 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
93 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
94 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
95 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
96};
97static_assert(sizeof(digitFromByte) == 256);
98
99[[nodiscard]] constexpr uchar digitFromChar(char chr) noexcept { return digitFromByte[static_cast<uchar>(chr)]; }
100
101constexpr inline char charconvDigits[2][37] = {
102 "0123456789abcdefghijklmnopqrstuvwxyz",
103 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
104};
105
106[[nodiscard]] constexpr char charFromInt(bool upper, uchar i) { return charconvDigits[upper][i]; }
123template <class T>
124 requires std::is_integral_v<T>
125[[nodiscard]] constexpr std::string
126intToHexStr(T value, bool upperCase = true, bool no0x = true, bool noLeadingZero = true) {
127 std::string result;
128 if (value < 0) result += '-';
129 if (!no0x) result += "0x";
130 bool leadingZero = true;
131 for (int i = sizeof(T) * 2; i > 0; --i) {
132 auto hex = static_cast<uchar>((value >> (i - 1) * 4) & 0xF);
133 if (noLeadingZero && leadingZero && hex == 0) continue;
134 leadingZero = false;
135 result += charFromInt(upperCase, hex);
136 }
137 return result;
138}
139
140[[nodiscard]] constexpr std::string strToHexStr(std::string_view value, bool upperCase = false, bool addSpace = false) {
141 std::string hex;
142 hex.reserve(value.size() * (addSpace ? 3 : 2));
143 for (uchar x : value) {
144 hex += charFromInt(upperCase, x / 16);
145 hex += charFromInt(upperCase, x % 16);
146 if (addSpace) hex += ' ';
147 }
148 if (addSpace && hex.ends_with(' ')) hex.pop_back();
149 return hex;
150}
151
152LLNDAPI std::string removeEscapeCode(std::string_view str);
153
154LLNDAPI std::string replaceAnsiToMcCode(std::string_view str);
155
156LLNDAPI std::string replaceMcToAnsiCode(std::string_view str);
157
158LLNDAPI bool isu8str(std::string_view str) noexcept;
159
160LLNDAPI std::string tou8str(std::string_view str);
161
162LLNDAPI std::string toSnakeCase(std::string_view str);
163
164LLNDAPI std::string toLowerCase(std::string_view str);
165
166namespace CodePage {
167enum : uint {
168 DefaultACP = 0, // default to ANSI code page
169 ThreadACP = 3, // current thread's ANSI code page
170 Symbol = 42, // SYMBOL translations
171 GB2312 = 936,
172 UTF8 = 65001,
173};
174} // namespace CodePage
175
176LLNDAPI std::wstring str2wstr(std::string_view str, uint codePage = CodePage::UTF8);
177
178LLNDAPI std::string wstr2str(std::wstring_view wstr, uint codePage = CodePage::UTF8);
179
180LLNDAPI std::string
181 str2str(std::string_view str, uint fromCodePage = CodePage::DefaultACP, uint toCodePage = CodePage::UTF8);
182
183[[nodiscard]] inline std::string u8str2str(std::u8string str) {
184 std::string& tmp = *reinterpret_cast<std::string*>(&str);
185 return {std::move(tmp)};
186}
187
188[[nodiscard]] inline std::u8string str2u8str(std::string str) {
189 std::u8string& tmp = *reinterpret_cast<std::u8string*>(&str);
190 return {std::move(tmp)};
191}
192
193[[nodiscard]] inline std::string const& u8str2strConst(std::u8string const& str) {
194 return *reinterpret_cast<std::string const*>(&str);
195}
196
197[[nodiscard]] inline std::u8string const& str2u8strConst(std::string const& str) {
198 return *reinterpret_cast<std::u8string const*>(&str);
199}
200
201[[nodiscard]] inline std::string_view u8sv2sv(std::u8string_view str) {
202 return {reinterpret_cast<char const*>(str.data()), str.size()};
203}
204
205[[nodiscard]] inline std::u8string_view sv2u8sv(std::string_view str) {
206 return {reinterpret_cast<char8_t const*>(str.data()), str.size()};
207}
208
209LLNDAPI Expected<bool> svtobool(std::string_view);
210
211template <class T, class... Args>
212[[nodiscard]] LL_CONSTEXPR23 Expected<T> svtonum(std::string_view str, size_t* idx, Args&&... args) {
213 T result;
214 const auto ans = ::std::from_chars(&*str.begin(), &*str.end(), result, std::forward<Args>(args)...);
215 if (ans.ec != std::errc{}) {
216 return makeErrorCodeError(ans.ec);
217 }
218 if (idx) {
219 *idx = static_cast<size_t>(ans.ptr - &*str.begin());
220 }
221 return result;
222}
223[[nodiscard]] inline decltype(auto) svtoc(std::string_view str, size_t* idx = nullptr, int base = 10) {
224 return svtonum<schar>(str, idx, base);
225}
226[[nodiscard]] inline decltype(auto) svtouc(std::string_view str, size_t* idx = nullptr, int base = 10) {
227 return svtonum<uchar>(str, idx, base);
228}
229[[nodiscard]] inline decltype(auto) svtos(std::string_view str, size_t* idx = nullptr, int base = 10) {
230 return svtonum<short>(str, idx, base);
231}
232[[nodiscard]] inline decltype(auto) svtous(std::string_view str, size_t* idx = nullptr, int base = 10) {
233 return svtonum<ushort>(str, idx, base);
234}
235[[nodiscard]] inline decltype(auto) svtoi(std::string_view str, size_t* idx = nullptr, int base = 10) {
236 return svtonum<int>(str, idx, base);
237}
238[[nodiscard]] inline decltype(auto) svtoui(std::string_view str, size_t* idx = nullptr, int base = 10) {
239 return svtonum<uint>(str, idx, base);
240}
241[[nodiscard]] inline decltype(auto) svtol(std::string_view str, size_t* idx = nullptr, int base = 10) {
242 return svtonum<long>(str, idx, base);
243}
244[[nodiscard]] inline decltype(auto) svtoul(std::string_view str, size_t* idx = nullptr, int base = 10) {
245 return svtonum<ulong>(str, idx, base);
246}
247[[nodiscard]] inline decltype(auto) svtoll(std::string_view str, size_t* idx = nullptr, int base = 10) {
248 return svtonum<int64>(str, idx, base);
249}
250[[nodiscard]] inline decltype(auto) svtoull(std::string_view str, size_t* idx = nullptr, int base = 10) {
251 return svtonum<uint64>(str, idx, base);
252}
253[[nodiscard]] inline decltype(auto)
254svtof(std::string_view str, size_t* idx = nullptr, std::chars_format format = std::chars_format::general) {
255 return svtonum<float>(str, idx, format);
256}
257[[nodiscard]] inline decltype(auto)
258svtod(std::string_view str, size_t* idx = nullptr, std::chars_format format = std::chars_format::general) {
259 return svtonum<double>(str, idx, format);
260}
261[[nodiscard]] inline decltype(auto)
262svtold(std::string_view str, size_t* idx = nullptr, std::chars_format format = std::chars_format::general) {
263 return svtonum<ldouble>(str, idx, format);
264}
265
266} // namespace ll::inline utils::string_utils