lxgui
Loading...
Searching...
No Matches
utils_string.cpp
1#include "lxgui/utils_string.hpp"
2
3#include <sstream>
4#include <utf8.h>
5
8namespace lxgui::utils {
9
10string_view trim(string_view s, char c_pattern) {
11 std::size_t start = s.find_first_not_of(c_pattern);
12 if (start == s.npos)
13 return {};
14
15 s = s.substr(start);
16
17 std::size_t end = s.find_last_not_of(c_pattern);
18 if (end != s.npos)
19 s = s.substr(0, end + 1);
20
21 return s;
22}
23
24string_view trim(string_view s, string_view patterns) {
25 std::size_t start = s.find_first_not_of(patterns);
26 if (start == s.npos)
27 return {};
28
29 s = s.substr(start);
30
31 std::size_t end = s.find_last_not_of(patterns);
32 if (end != s.npos)
33 s = s.substr(0, end + 1);
34
35 return s;
36}
37
38void replace(string& s, string_view pattern, string_view replacement) {
39 std::size_t pos = s.find(pattern);
40
41 while (pos != s.npos) {
42 s.replace(pos, pattern.length(), replacement);
43 pos = s.find(pattern, pos + replacement.length());
44 }
45}
46
47std::size_t count_occurrences(string_view s, string_view pattern) {
48 std::size_t count = 0;
49 std::size_t pos = s.find(pattern);
50 while (pos != s.npos) {
51 ++count;
52 pos = s.find(pattern, pos + 1);
53 }
54
55 return count;
56}
57
58template<typename T>
59std::vector<std::basic_string_view<T>>
60cut_template(std::basic_string_view<T> s, std::basic_string_view<T> delim) {
61 std::vector<std::basic_string_view<T>> pieces;
62 std::size_t pos = s.find(delim);
63 std::size_t last_pos = 0u;
64 std::size_t cur_size = 0u;
65
66 while (pos != std::basic_string_view<T>::npos) {
67 cur_size = pos - last_pos;
68 if (cur_size != 0)
69 pieces.push_back(s.substr(last_pos, cur_size));
70 last_pos = pos + delim.size();
71 pos = s.find(delim, last_pos);
72 }
73
74 pieces.push_back(s.substr(last_pos));
75
76 return pieces;
77}
78
79std::vector<string_view> cut(string_view s, string_view delim) {
80 return cut_template(s, delim);
81}
82
83std::vector<ustring_view> cut(ustring_view s, ustring_view delim) {
84 return cut_template(s, delim);
85}
86
87template<typename T>
88std::vector<std::basic_string_view<T>>
89cut_each_template(std::basic_string_view<T> s, std::basic_string_view<T> delim) {
90 std::vector<std::basic_string_view<T>> pieces;
91 std::size_t pos = s.find(delim);
92 std::size_t last_pos = 0u;
93 std::size_t cur_size = 0u;
94
95 while (pos != std::basic_string_view<T>::npos) {
96 cur_size = pos - last_pos;
97 pieces.push_back(s.substr(last_pos, cur_size));
98 last_pos = pos + delim.size();
99 pos = s.find(delim, last_pos);
100 }
101
102 pieces.push_back(s.substr(last_pos));
103
104 return pieces;
105}
106
107std::vector<string_view> cut_each(string_view s, string_view delim) {
108 return cut_each_template(s, delim);
109}
110
111std::vector<ustring_view> cut_each(ustring_view s, ustring_view delim) {
112 return cut_each_template(s, delim);
113}
114
115template<typename T>
116std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
117cut_first_template(std::basic_string_view<T> s, std::basic_string_view<T> delim) {
118 std::size_t pos = s.find(delim);
119 if (pos == std::basic_string_view<T>::npos)
120 return {};
121
122 return {s.substr(0, pos), s.substr(pos + 1u)};
123}
124
125std::pair<string_view, string_view> cut_first(string_view s, string_view delim) {
126 return cut_first_template(s, delim);
127}
128
129std::pair<ustring_view, ustring_view> cut_first(ustring_view s, ustring_view delim) {
130 return cut_first_template(s, delim);
131}
132
133bool has_no_content(string_view s) {
134 if (s.empty())
135 return true;
136
137 for (std::size_t i = 0; i < s.length(); ++i) {
138 if (s[i] != ' ' && s[i] != '\t')
139 return false;
140 }
141
142 return true;
143}
144
145bool starts_with(string_view s, string_view pattern) {
146 std::size_t n = std::min(s.size(), pattern.size());
147 for (std::size_t i = 0; i < n; ++i) {
148 if (s[i] != pattern[i])
149 return false;
150 }
151
152 return true;
153}
154
155bool ends_with(string_view s, string_view pattern) {
156 std::size_t ss = s.size();
157 std::size_t ps = pattern.size();
158 std::size_t n = std::min(ss, ps);
159 for (std::size_t i = 1; i <= n; ++i) {
160 if (s[ss - i] != pattern[ps - i])
161 return false;
162 }
163
164 return true;
165}
166
167ustring utf8_to_unicode(string_view s) {
168 return utf8::utf8to32(s);
169}
170
171string unicode_to_utf8(ustring_view s) {
172 return utf8::utf32to8(s);
173}
174
175std::size_t hex_to_uint(string_view s) {
176 std::size_t i = 0;
177 std::istringstream ss{std::string(s)};
178 ss.imbue(std::locale::classic());
179 ss >> std::hex >> i;
180 return i;
181}
182
183namespace impl {
184
185template<typename T>
186std::optional<T> from_string_template(const std::locale& loc, string_view s) {
187 std::istringstream ss{std::string(s)};
188 ss.imbue(loc);
189
190 T v;
191 ss >> v;
192
193 if (!ss.fail()) {
194 if (ss.eof())
195 return v;
196
197 std::string rem;
198 ss >> rem;
199
200 if (rem.find_first_not_of(" \t") == rem.npos)
201 return v;
202 }
203
204 return {};
205}
206
207template<typename T>
208std::optional<T> from_string_template(const std::locale& loc, ustring_view s) {
209 return from_string_template<T>(loc, unicode_to_utf8(s));
210}
211
212// ----- locale, utf8 string
213
214template<>
215std::optional<int> from_string<int>(const std::locale& loc, string_view s) {
216 return from_string_template<int>(loc, s);
217}
218
219template<>
220std::optional<long> from_string<long>(const std::locale& loc, string_view s) {
221 return from_string_template<long>(loc, s);
222}
223
224template<>
225std::optional<long long> from_string<long long>(const std::locale& loc, string_view s) {
226 return from_string_template<long long>(loc, s);
227}
228
229template<>
230std::optional<unsigned> from_string<unsigned>(const std::locale& loc, string_view s) {
231 return from_string_template<unsigned>(loc, s);
232}
233
234template<>
235std::optional<unsigned long> from_string<unsigned long>(const std::locale& loc, string_view s) {
236 return from_string_template<unsigned long>(loc, s);
237}
238
239template<>
240std::optional<unsigned long long>
241from_string<unsigned long long>(const std::locale& loc, string_view s) {
242 return from_string_template<unsigned long long>(loc, s);
243}
244
245template<>
246std::optional<float> from_string<float>(const std::locale& loc, string_view s) {
247 return from_string_template<float>(loc, s);
248}
249
250template<>
251std::optional<double> from_string<double>(const std::locale& loc, string_view s) {
252 return from_string_template<double>(loc, s);
253}
254
255// ----- locale, utf32 string
256
257template<>
258std::optional<int> from_string<int>(const std::locale& loc, ustring_view s) {
259 return from_string_template<int>(loc, s);
260}
261
262template<>
263std::optional<long> from_string<long>(const std::locale& loc, ustring_view s) {
264 return from_string_template<long>(loc, s);
265}
266
267template<>
268std::optional<long long> from_string<long long>(const std::locale& loc, ustring_view s) {
269 return from_string_template<long long>(loc, s);
270}
271
272template<>
273std::optional<unsigned> from_string<unsigned>(const std::locale& loc, ustring_view s) {
274 return from_string_template<unsigned>(loc, s);
275}
276
277template<>
278std::optional<unsigned long> from_string<unsigned long>(const std::locale& loc, ustring_view s) {
279 return from_string_template<unsigned long>(loc, s);
280}
281
282template<>
283std::optional<unsigned long long>
284from_string<unsigned long long>(const std::locale& loc, ustring_view s) {
285 return from_string_template<unsigned long long>(loc, s);
286}
287
288template<>
289std::optional<float> from_string<float>(const std::locale& loc, ustring_view s) {
290 return from_string_template<float>(loc, s);
291}
292
293template<>
294std::optional<double> from_string<double>(const std::locale& loc, ustring_view s) {
295 return from_string_template<double>(loc, s);
296}
297
298// ----- C locale, utf8 string
299
300template<>
301std::optional<int> from_string<int>(string_view s) {
302 return from_string_template<int>(std::locale::classic(), s);
303}
304
305template<>
306std::optional<long> from_string<long>(string_view s) {
307 return from_string_template<long>(std::locale::classic(), s);
308}
309
310template<>
311std::optional<long long> from_string<long long>(string_view s) {
312 return from_string_template<long long>(std::locale::classic(), s);
313}
314
315template<>
316std::optional<unsigned> from_string<unsigned>(string_view s) {
317 return from_string_template<unsigned>(std::locale::classic(), s);
318}
319
320template<>
321std::optional<unsigned long> from_string<unsigned long>(string_view s) {
322 return from_string_template<unsigned long>(std::locale::classic(), s);
323}
324
325template<>
326std::optional<unsigned long long> from_string<unsigned long long>(string_view s) {
327 return from_string_template<unsigned long long>(std::locale::classic(), s);
328}
329
330template<>
331std::optional<float> from_string<float>(string_view s) {
332 return from_string_template<float>(std::locale::classic(), s);
333}
334
335template<>
336std::optional<double> from_string<double>(string_view s) {
337 return from_string_template<double>(std::locale::classic(), s);
338}
339
340template<>
341std::optional<bool> from_string<bool>(string_view s) {
342 if (s == "true")
343 return true;
344 if (s == "false")
345 return false;
346 return {};
347}
348
349template<>
350std::optional<string> from_string<string>(string_view s) {
351 return string{s};
352}
353
354// ----- C locale, utf32 string
355
356template<>
357std::optional<int> from_string<int>(ustring_view s) {
358 return from_string_template<int>(std::locale::classic(), s);
359}
360
361template<>
362std::optional<long> from_string<long>(ustring_view s) {
363 return from_string_template<long>(std::locale::classic(), s);
364}
365
366template<>
367std::optional<long long> from_string<long long>(ustring_view s) {
368 return from_string_template<long long>(std::locale::classic(), s);
369}
370
371template<>
372std::optional<unsigned> from_string<unsigned>(ustring_view s) {
373 return from_string_template<unsigned>(std::locale::classic(), s);
374}
375
376template<>
377std::optional<unsigned long> from_string<unsigned long>(ustring_view s) {
378 return from_string_template<unsigned long>(std::locale::classic(), s);
379}
380
381template<>
382std::optional<unsigned long long> from_string<unsigned long long>(ustring_view s) {
383 return from_string_template<unsigned long long>(std::locale::classic(), s);
384}
385
386template<>
387std::optional<float> from_string<float>(ustring_view s) {
388 return from_string_template<float>(std::locale::classic(), s);
389}
390
391template<>
392std::optional<double> from_string<double>(ustring_view s) {
393 return from_string_template<double>(std::locale::classic(), s);
394}
395
396template<>
397std::optional<bool> from_string<bool>(ustring_view s) {
398 if (s == U"true")
399 return true;
400 if (s == U"false")
401 return false;
402 return {};
403}
404
405template<>
406std::optional<ustring> from_string<ustring>(ustring_view s) {
407 return ustring{s};
408}
409
410} // namespace impl
411
412bool is_number(const std::locale& loc, string_view s) {
413 return impl::from_string<double>(loc, s).has_value();
414}
415
416bool is_number(const std::locale& loc, ustring_view s) {
417 return impl::from_string<double>(loc, s).has_value();
418}
419
420bool is_integer(const std::locale& loc, string_view s) {
421 return impl::from_string<std::int64_t>(loc, s).has_value();
422}
423
424bool is_integer(const std::locale& loc, ustring_view s) {
425 return impl::from_string<std::int64_t>(loc, s).has_value();
426}
427
428bool is_number(string_view s) {
429 return is_number(std::locale::classic(), s);
430}
431
432bool is_number(ustring_view s) {
433 return is_number(std::locale::classic(), s);
434}
435
436bool is_integer(string_view s) {
437 return is_integer(std::locale::classic(), s);
438}
439
440bool is_integer(ustring_view s) {
441 return is_integer(std::locale::classic(), s);
442}
443
444bool is_number(char s) {
445 return '0' <= s && s <= '9';
446}
447
448bool is_number(char32_t s) {
449 return U'0' <= s && s <= U'9';
450}
451
452bool is_integer(char s) {
453 return is_number(s);
454}
455
456bool is_integer(char32_t s) {
457 return is_number(s);
458}
459
460bool is_boolean(string_view s) {
461 return (s == "false") || (s == "true");
462}
463
464bool is_boolean(ustring_view s) {
465 return (s == U"false") || (s == U"true");
466}
467
468bool is_whitespace(char c) {
469 return c == '\n' || c == ' ' || c == '\t' || c == '\r';
470}
471
472bool is_whitespace(char32_t c) {
473 return c == U'\n' || c == U' ' || c == U'\t' || c == '\r';
474}
475
476template<typename T>
477string to_string_template(T value) {
478 std::ostringstream ss;
479 ss.imbue(std::locale::classic());
480 ss << value;
481 return ss.str();
482}
483
484string to_string(int v) {
485 return to_string_template(v);
486}
487
488string to_string(long v) {
489 return to_string_template(v);
490}
491
492string to_string(long long v) {
493 return to_string_template(v);
494}
495
496string to_string(unsigned v) {
497 return to_string_template(v);
498}
499
500string to_string(unsigned long v) {
501 return to_string_template(v);
502}
503
504string to_string(unsigned long long v) {
505 return to_string_template(v);
506}
507
508string to_string(float v) {
509 return to_string_template(v);
510}
511
512string to_string(double v) {
513 return to_string_template(v);
514}
515
516string to_string(bool b) {
517 return b ? "true" : "false";
518}
519
520string to_string(const void* p) {
521 std::ostringstream stream;
522 stream.imbue(std::locale::classic());
523 stream << p;
524 return stream.str();
525}
526
527string to_string(const utils::variant& value) {
528 return std::visit(
529 [&](const auto& inner_value) -> std::string {
530 using inner_type = std::decay_t<decltype(inner_value)>;
531 if constexpr (std::is_same_v<inner_type, utils::empty>)
532 return "<none>";
533 else
534 return to_string(inner_value);
535 },
536 value);
537}
538
539string to_lower(string str) {
540 for (char& c : str)
541 c = static_cast<char>(std::tolower(c));
542
543 return str;
544}
545
546} // namespace lxgui::utils
547
range_impl::value_range< T > value(T &container)
Expose the value rather than the (key,value) pair.
std::variant< empty, bool, std::int64_t, std::int32_t, std::int16_t, std::int8_t, std::uint64_t, std::uint32_t, std::uint16_t, std::uint8_t, double, float, std::string > variant
Type-erased value for passing arguments to events.
STL namespace.