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