dl
dl_string.h
浏览该文件的文档.
1
21#pragma once
22#include <array>
23#include <string>
24#include <system_error>
25#include <charconv>
26
27#include <fmt/format.h>
28
29#include "memory/dl_code_cvt.h"
30#include "dl_range.h"
31#include "math/dl_algorithm.h"
32#include "io/dl_log.h"
33#include "base/dl_type_def.h"
34#include "base/dl_vector2.h"
35#include "base/dl_array2.h"
36#include "memory/dl_buffer.h"
37
38namespace dl
39{
40
41
42// unordered_map支持 string_view
44{
45 using hash_type = std::hash<std::string_view>;
46 using is_transparent = void;
47
48 std::size_t operator()(const char* str) const { return hash_type{}(str); }
49 std::size_t operator()(std::string_view str) const { return hash_type{}(str); }
50 std::size_t operator()(std::string const& str) const { return hash_type{}(str); }
51};
52
53//-----------------------------字符串连接-------------------
54inline std::string& operator+=(std::string& a, std::string_view b)
55{
56 a.append(b);
57 return a;
58}
59inline std::string operator+(const std::string& a, std::string_view b)
60{
61 std::string ret{ a };
62 return ret += b;
63}
64inline std::string operator+(std::string_view a, std::string_view b)
65{
66 std::string ret{ a };
67 return ret += b;
68}
69
73template<IsBase T>
74std::string to_string(T v)
75{
76 if constexpr (std::is_floating_point_v<T>)
77 {
78 return fmt::format("{:.2f}", v);
79 }
80 else
81 return std::to_string(v);
82}
83
84inline std::string to_string(const std::string& str)
85{
86 return str;
87}
88
92template<typename T, size_t N>
93std::string to_string(const std::array<T, N>& arr, std::string_view delimiter = ", ")
94{
95 static_assert(N != 0);
96 std::string ret;
97 for (size_t i = 0; i < N - 1; ++i)
98 {
99 ret += dl::to_string(arr[i]);
100 ret += delimiter;
101 }
102 ret += dl::to_string(arr[N - 1]);
103 return ret;
104}
105template<typename T, size_t N>
106std::string to_string(const Array<T, N>& arr, std::string_view delimiter = ", ")
107{
108 static_assert(N != 0);
109 std::string ret;
110 for (size_t i = 0; i < N - 1; ++i)
111 {
112 ret += dl::to_string(arr[i]);
113 ret += delimiter;
114 }
115 ret += dl::to_string(arr[N - 1]);
116 return ret;
117}
118template<typename T, size_t N>
119std::string to_string(const ArrayS2<T, N>& arr, std::string_view delimiter = ", ")
120{
121 static_assert(N != 0);
122 std::string ret;
123 for (size_t i = 0; i < N - 1; ++i)
124 {
125 ret += dl::to_string(arr.x[i]);
126 ret += delimiter;
127 ret += dl::to_string(arr.y[i]);
128 ret += delimiter;
129 }
130 ret += dl::to_string(arr.x[N - 1]);
131 ret += delimiter;
132 ret += dl::to_string(arr.y[N - 1]);
133 return ret;
134}
135
138template<typename T>
139std::string to_string(const std::vector<T>& vec, std::string_view delimiter = ", ")
140{
141 if (vec.empty())
142 return {};
143 std::string ret;
144 for (size_t i = 0; i < vec.size() - 1; ++i)
145 {
146 ret += dl::to_string(vec[i]);
147 ret += delimiter;
148 }
149 ret += dl::to_string(vec[vec.size() - 1]);
150 return ret;
151}
152
154std::string to_string(std::error_code code);
155
157std::string to_string(std::exception& e);
158
162std::string to_string(BufferView buf);
163
164inline std::string to_string(const Buffer& buf)
165{
166 return to_string(BufferView{ buf });
167}
168
172std::string to_string_check(BufferView buf, bool tips = true);
173
177std::string to_string_hex(BufferView buf, bool upper = false, bool add_tag = false);
178
182template<size_t N>
183std::string to_string_hex(const std::array<std::byte, N>& buf, bool upper = false, bool add_tag = false)
184{
185 return to_string_hex(CreateBufferView(buf), add_tag);
186}
187
191std::string to_string_auto(BufferView buf, bool add_tag = false);
192
199
200namespace String
201{
206inline Float toFloat(std::string_view str, Float default_v = 0)
207{
208#if DL_PLATFORM != DL_PLATFORM_APPLE
209 std::from_chars(str.data(), str.data() + str.size(), default_v);
210 return default_v;
211#else
212 if (str.empty())
213 return default_v;
214
215 if constexpr (std::is_same_v<Float, float>)
216 {
217 try
218 {
219 return std::stof(str.data());
220 }
221 catch (...)
222 {
223 return default_v;
224 }
225 }
226 else if constexpr (std::is_same_v<Float, double>)
227 {
228 try
229 {
230 return std::stod(str.data());
231 }
232 catch (...)
233 {
234 return default_v;
235 }
236 }
237#endif
238}
239
242inline bool IsBlank(char ch)
243{
244 return ch == ' '
245 || ch == '\n'
246 || ch == '\t';
247}
248
251inline std::vector<std::string_view> ToView(const std::vector<std::string>& a)
252{
253 std::vector<std::string_view> ret;
254 for (auto& iter : a)
255 {
256 ret.push_back(iter);
257 }
258 return ret;
259}
260
264inline bool IsBlank(std::string_view str)
265{
266 for (char ch : str)
267 {
268 if (!IsBlank(ch))
269 return false;
270 }
271 return true;
272}
273
277inline std::string_view EraseBlankBoth(std::string_view str)
278{
279 auto iter = str.begin();
280 while (iter != str.end() && IsBlank(*iter))
281 {
282 ++iter;
283 }
284 auto iter1 = str.rbegin();
285 while (iter1 != str.rend() && IsBlank(*iter1))
286 {
287 ++iter1;
288 }
289
290 return { iter, iter1.base() };
291}
292
296inline int toInt(std::string_view str, int default_v = 0)
297{
298#if DL_PLATFORM != DL_PLATFORM_APPLE
299 std::from_chars(str.data(), str.data() + str.size(), default_v);
300 return default_v;
301#else
302 try
303 {
304 return std::stoi(str.data());
305 }
306 catch (...)
307 {
308 return default_v;
309 }
310#endif
311}
312inline unsigned toUint(std::string_view str, unsigned default_v = 0)
313{
314#if DL_PLATFORM != DL_PLATFORM_APPLE
315 std::from_chars(str.data(), str.data() + str.size(), default_v);
316 return default_v;
317#else
318 try
319 {
320 return std::stoul(str.data());
321 }
322 catch (...)
323 {
324 return default_v;
325 }
326#endif
327}
328
332inline int64_t toInt64(std::string_view str, int64_t default_v = 0)
333{
334#if DL_PLATFORM != DL_PLATFORM_APPLE
335 std::from_chars(str.data(), str.data() + str.size(), default_v);
336 return default_v;
337#else
338 try
339 {
340 return std::stoll(str.data());
341 }
342 catch (...)
343 {
344 return default_v;
345 }
346#endif
347}
348
351inline bool getInt(std::string_view str, int& ret)
352{
353#if DL_PLATFORM != DL_PLATFORM_APPLE
354 std::from_chars_result r = std::from_chars(str.data(), str.data() + str.size(), ret);
355 return r.ec == std::errc();
356#else
357 try
358 {
359 ret = std::stoi(str.data());
360 }
361 catch (...)
362 {
363 return false;
364 }
365 return true;
366#endif
367}
368
373inline bool toBool(std::string_view str, bool default_v = false)
374{
375 return toInt(str, default_v);
376}
377
380inline bool getByte(std::string_view str, std::byte& ret)
381{
382
383#if DL_PLATFORM != DL_PLATFORM_APPLE
384 uint8_t v;
385 std::from_chars_result r = std::from_chars(str.data(), str.data() + str.size(), v, 16);
386 if (r.ec != std::errc())
387 return false;
388 ret = (std::byte)v;
389 return true;
390#else
391 try
392 {
393 ret = std::stoi(str.data(), nullptr, 16);
394 }
395 catch (...)
396 {
397 return false;
398 }
399 return true;
400#endif
401}
402
405template<std::size_t N>
406Array<int, N> toPoint(std::string_view str, char d = ',')
407{
408 std::vector<std::string_view> vec;
409 split_no_empty(str, d, vec);
410 if (vec.size() != N)
411 {
412 log_warn("分割后数量不匹配,将丢弃或填充0:{}/{}", vec.size(), N);
413 vec.resize(N);
414 }
415
416 Array<int, N> ret;
417 for (size_t i = 0; i < N; ++i)
418 {
419 std::string_view s = EraseBlankBoth(vec[i]);
420 ret[i] = toInt(s);
421 }
422 return ret;
423}
424
427template<std::size_t N>
428Array<Float, N> toPosition(std::string_view str, char d = ',')
429{
430 std::vector<std::string_view> vec;
431 split_no_empty(str, d, vec);
432 if (vec.size() != N)
433 {
434 log_warn("分割后数量不匹配,将丢弃或填充0:{}/{}", vec.size(), N);
435 vec.resize(N);
436 }
437
438 Array<Float, N> ret;
439 for (size_t i = 0; i < N; ++i)
440 {
441 std::string_view s = EraseBlankBoth(vec[i]);
442 ret[i] = toFloat(s);
443 }
444 return ret;
445}
446
447inline Point2 toPoint2(std::string_view str, char d = ',')
448{
449 return toPoint<2>(str, d);
450}
451inline Position toPosition2(std::string_view str, char d = ',')
452{
453 return toPosition<2>(str, d);
454}
455
459constexpr StringType GetType(std::string_view str)
460{
461 bool has_dot = false;
462 for (size_t i = 0; i < str.size(); ++i)
463 {
464 const char& ch = str[i];
465 if (std::isdigit(ch))
466 continue;
467 else if (i == 0 && (ch == '+' || ch == '-'))
468 continue;
469 else if (!has_dot && ch == '.')
470 {
471 has_dot = true;
472 continue;
473 }
474 else
475 return StringType::NORMAL;
476 }
477 return has_dot ? StringType::FLOAT : StringType::INTGER;
478}
479
482inline std::string AddQuotes(std::string_view str, char quotes = '\"')
483{
484 std::string ret;
485 ret.reserve(str.size() + 2);
486 ret += quotes;
487 ret += str;
488 ret += quotes;
489 return ret;
490}
491
494size_t Wcwidth(wchar_t ch);
499std::string FillEndl(std::string_view str, char ch = ' ');
503constexpr std::string_view GetNotFileName()
504{
505 return R"(<>/\|:"*?)";
506}
507
511inline void EraseNotFileName(std::string& name)
512{
513 Erase::Match(name, std::string{ String::GetNotFileName() });
514}
515
519inline void ToLower(std::string& str)
520{
521 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
522}
523
527inline std::string ToLower(const std::string& str)
528{
529 std::string ret = str;
530 std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
531 return ret;
532}
536inline void ToUpper(std::string& str)
537{
538 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
539}
543inline std::string ToUpper(std::string_view str)
544{
545 std::string ret{ str };
546 ToUpper(ret);
547 return ret;
548}
552inline bool EqualToLower(std::string_view a, std::string_view b)
553{
554 if (a.size() != b.size())
555 return false;
556 if (a.empty())
557 return true;
558 for (size_t i = 0; i < a.size(); ++i)
559 {
560 if (std::tolower(a[i]) != std::tolower(b[i]))
561 return false;
562 }
563 return true;
564}
565
566
571inline bool toBoolEx(std::string_view str, bool default_v = false)
572{
573 int v;
574 if (getInt(str, v))
575 return v;
576 else if (String::EqualToLower(str, "true"))
577 return true;
578 else if (String::EqualToLower(str, "false"))
579 return false;
580 return default_v;
581}
582
586inline std::string Splicing(const std::vector<std::string>& vec,
587 std::string_view delimiter = ", ", std::string_view end = "")
588{
589 if (vec.empty())
590 return {};
591 if (vec.size() == 1)
592 return vec[0] + end;
593
594 std::string ret;
595 for (size_t i = 0; i < vec.size() - 1; ++i)
596 {
597 ret += vec[i];
598 ret += delimiter;
599 }
600 ret += vec[vec.size() - 1];
601 ret += end;
602 return ret;
603}
608inline std::string EraseCharAll(std::string_view str, std::string_view vec_char)
609{
610 std::string ret;
611 for (auto& iter : str)
612 {
613 if (Every::NotEqual(vec_char, iter))
614 ret.push_back(iter);
615 }
616 return ret;
617}
622inline std::string EraseCharN(std::string_view str, std::string_view vec_char, size_t n = 1)
623{
624 std::string ret;
625
626 for (auto& iter : str)
627 {
628 if (n && Any::Equal(vec_char, iter))
629 {
630 --n;
631 continue;
632 }
633 else
634 ret.push_back(iter);
635 }
636 return ret;
637}
642inline std::string EraseCharHead(std::string_view str, std::string_view vec_char)
643{
644 std::string ret;
645
646 bool check = true;
647 for (auto& iter : str)
648 {
649 if (check)
650 {
651 if (Any::Equal(vec_char, iter))
652 ;// 需要删除,仍需判断
653 else
654 {
655 check = false;
656 ret.push_back(iter);
657 }
658 }
659 else
660 ret.push_back(iter);
661 }
662 return ret;
663}
667inline std::string EraseBlank(std::string_view str)
668{
669 return EraseCharAll(str, " \t\n");
670}
674inline std::string EraseBlankN(std::string_view str, size_t n = 1)
675{
676 return EraseCharN(str, " \t\n", n);
677}
681inline std::string EraseBlankHead(std::string_view str)
682{
683 return EraseCharHead(str, " \t\n");
684}
688inline std::string EraseEndl(std::string_view str)
689{
690 if (str.empty())
691 return {};
692
693 size_t i = str.size() - 1;
694 for (; i >= 0; --i)
695 {
696 if (str[i] != '\n' && str[i] != '\r')
697 break;
698 }
699 return { str.data(), str.data() + i + 1 };
700}
701
705inline std::string GetUtf8ByWchar(wchar_t wc, size_t offset = 0)
706{
707 // 某些平台wchar_t是4字节,必须使用u32string
708 std::u32string s{ (char32_t)(wc + offset) };
709
710 return CodeCvt::Utf32ToUtf8(s);
711}
712
713
717//string GetAscii()
718//{
719// string str_ascii = format("ascii表:\n0 -> /0[t_8]");
720// for (char ch = 1; ch < 128; ++ch)
721// {
722// if (ch == '\n')
723// str_ascii += format("{} -> {}[t_8]", to_string(ch), "/n");
724// else if (ch == '\t')
725// str_ascii += format("{} -> {}[t_8]", to_string(ch), "/t");
726// else if (ch == '[')
727// str_ascii += format("{} -> {}[t_8]", to_string(ch), "[l]");
728// else if (ch == ']')
729// str_ascii += format("{} -> {}[t_8]", to_string(ch), "[r]");
730// else
731// str_ascii += format("{} -> {}[t_8]", to_string(ch), char(ch));
732//
733// if ((ch - 1) % 6 == 0)
734// str_ascii += "\n";
735// }
736// return str_ascii;
737//}
738
742std::string Sprintf(const char* format, ...);
743
747template<typename T>
748std::string SplitIntegerToThousands(T integer)
749{
750 return r_insert_per_num(to_string(integer), ',', 3);
751}
752
756inline std::vector<std::string> Split(const std::string& str, char d)
757{
758 std::vector<std::string> ret;
759 split(str, d, ret);
760 return ret;
761}
762inline std::vector<std::string_view> SplitView(std::string_view str, char d)
763{
764 std::vector<std::string_view> ret;
765 split(str, d, ret);
766 return ret;
767}
768
772inline std::vector<std::string> Split(const std::string& str, const std::string& d)
773{
774 std::vector<std::string> ret;
775 split_sub(str, d, ret);
776 return ret;
777}
778inline std::vector<std::string_view> SplitView(std::string_view str, std::string_view d)
779{
780 std::vector<std::string_view> ret;
781 split_sub(str, d, ret);
782 return ret;
783}
784
788inline std::vector<std::string> SplitNoEmpty(const std::string& str, char d)
789{
790 std::vector<std::string> ret;
791 split_no_empty(str, d, ret);
792 return ret;
793}
794
798inline std::vector<std::string_view> SplitViewNoEmpty(std::string_view str, char d)
799{
800 std::vector<std::string_view> ret;
801 split_no_empty(str, d, ret);
802 return ret;
803}
804
805
812inline std::vector<std::string_view> SplitViewNoEmpty(std::string_view str, std::string_view vec_ch)
813{
814 std::vector<std::string_view> ret;
815 size_t beg = 0;
816 size_t cur = 0;
817 for (; cur < str.size(); ++cur)
818 {
819 if (Any::Equal(vec_ch, str[cur]))
820 {
821 if (beg != cur)
822 ret.push_back({ str.data() + beg, str.data() + cur });
823 beg = cur + 1;
824 }
825 }
826 if (beg != cur)
827 ret.push_back({ str.data() + beg, str.data() + cur });
828 return ret;
829}
830inline std::vector<std::string_view> SplitViewNoEmpty(std::string_view str,
831 const std::vector<char>& vec_ch)
832{
833 return SplitViewNoEmpty(str, std::string_view{ vec_ch.data(), vec_ch.size() });
834}
836//* @brief 处理子字符串(通过特定字符分割)
837//* @param[in] str 整个字符串
838//* @param[in] vec_ch 匹配的字符
839//* @note 连续匹配返回空串
840//*/
841//inline std::vector<std::string_view> SplitView(std::string_view str, std::string_view vec_ch)
842//{
843// std::vector<std::string_view> ret;
844// size_t beg = 0;
845// size_t cur = 0;
846// for (; cur < str.size(); ++cur)
847// {
848// if (Any::Equal(vec_ch, str[cur]))
849// {
850// if (beg != cur)
851// ret.push_back({ str.data() + beg, str.data() + cur });
852// else
853// ret.push_back({});
854// beg = cur + 1;
855// }
856// }
857// if (beg != cur)
858// ret.push_back({ str.data() + beg, str.data() + cur });
859// else
860// ret.push_back({});
861// return ret;
862//}
863//inline std::vector<std::string_view> SplitView(std::string_view str,
864// const std::vector<char>& vec_ch)
865//{
866// return SplitView(str, std::string_view{ vec_ch.data(), vec_ch.size() });
867//}
868
869
870
875inline void EraseExtension(std::string& path_name)
876{
877 if (Erase::TailFromLast(path_name, '.'))
878 path_name.pop_back();
879}
880[[nodiscard]]
881inline std::string EraseExtension(std::string_view path_name)
882{
883 std::string ret = std::string{ path_name };
884 EraseExtension(ret);
885 return ret;
886}
887
894inline void ReplaceExtension(std::string& path_name, std::string_view fmt)
895{
896 if (Erase::TailFromLast(path_name, '.'))
897 {
898 path_name += fmt;
899 return;
900 }
901 path_name += ".";
902 path_name += std::string{ fmt };
903}
904[[nodiscard]]
905inline std::string ReplaceExtension(std::string_view path_name, std::string_view fmt)
906{
907 std::string ret = std::string{ path_name };
908 ReplaceExtension(ret, fmt);
909 return ret;
910}
911
916inline void EraseFilename(std::string& path_name)
917{
918 if (!Erase::TailFromLast(path_name, '/'))
919 log_err0("不是一个有效路径!");
920}
921[[nodiscard]]
922inline std::string EraseFilename(std::string_view path_name)
923{
924 std::string ret = std::string{ path_name };
925 EraseFilename(ret);
926 return ret;
927}
928
932inline std::string GetFileStem(std::string_view path_name)
933{
934 std::string name{ path_name };
935 Erase::HeadFromLast(name, '/');
936 if (Erase::TailFromLast(name, '.'))
937 name.pop_back();
938 return name;
939}
943inline std::string ErasePath(std::string_view path_name, std::string_view path)
944{
945 std::string ret{ path_name };
946 Erase::HeadSub(ret, std::string{ path });
947 return ret;
948}
949
955
956inline bool IsRelativePath(std::string_view path_name)
957{
958 if (path_name.empty())
959 return true;
960
961 if (path_name[0] == '/')
962 return false;
963
964 size_t len = (std::min)(path_name.size(), (size_t)12);
965 for (size_t i = 0; i < len; ++i)
966 {
967 if (path_name[i] == ':')
968 return false;
969 }
970 return true;
971}
972
973
983bool GetPathAndRes(
984 std::string_view path_root, std::string_view path_name,
985 std::string& path_real, std::string& res_name,
986 std::string_view name = "");
987
988
994std::string GetResName(
995 std::string_view path_root,
996 std::string_view path_name);
997
998
1005std::string CvtRelativePath(std::string path_cur, std::string_view path);
1006
1011inline void CvtPathSeparator(std::string& path)
1012{
1013 Every::Replace(path, '\\', '/');
1014}
1015[[nodiscard]]
1016inline std::string CvtPathSeparator(std::string_view path)
1017{
1018 std::string ret{ path };
1019 CvtPathSeparator(ret);
1020 return ret;
1021}
1026inline void CvtPathSeparatorBack(std::string& path)
1027{
1028 Every::Replace(path, '/', '\\');
1029}
1030[[nodiscard]]
1031inline std::string CvtPathSeparatorBack(std::string_view path)
1032{
1033 std::string ret{ path };
1034 CvtPathSeparatorBack(ret);
1035 return ret;
1036}
1041inline std::string CvtLineBreak(std::string_view str)
1042{
1043 std::string ret;
1044 for (auto& iter : str)
1045 {
1046 if(iter == '\r')
1047 continue;
1048 ret.push_back(iter);
1049 }
1050 return ret;
1051}
1052
1053
1057inline bool HasNumber(std::string_view str)
1058{
1059 return Any::Yes(str, isdigit);
1060}
1061
1065inline bool HasLetter(std::string_view str)
1066{
1067 return Any::Yes(str, isalpha);
1068}
1069
1073std::vector<std::string> ParseCommand(std::string_view cmd);
1074
1079template<size_t W, size_t H>
1080Array<std::string, H> FormatString2(const Array2<std::string, W, H>& arr)
1081{
1082 //每一列得到一个最大宽度
1083 Array<size_t, W> mul_col{};
1084 for (size_t j = 0; j < H; ++j)
1085 {
1086 for (size_t i = 0; i < W; ++i)
1087 {
1088 if (arr[j][i].size() > mul_col[i])
1089 mul_col[i] = arr[j][i].size();
1090 }
1091 }
1092 //合并每行
1093 Array<std::string, H> ret;
1094 for (size_t i = 0; i < W; ++i)
1095 {
1096 std::string fmt = std::string("{:<") + std::to_string(mul_col[i] + 1) + "}";
1097 for (size_t j = 0; j < H; ++j)
1098 {
1099 ret[j] += fmt::vformat(fmt, fmt::make_format_args(arr[j][i]));
1100 }
1101 }
1102 return ret;
1103}
1104
1109std::vector<std::string> FormatString2(const Vector2<std::string>& arr);
1110
1115inline std::string_view GetBeginUntilNumber(std::string_view str)
1116{
1117 size_t i = 0;
1118 while (i < str.size() && !std::isdigit((unsigned char)str[i]))
1119 {
1120 ++i;
1121 }
1122 return str.substr(0, i);
1123}
1124
1125//----------------------------其余范围操作封装----------------------------
1126inline bool IsSub(std::string_view str, std::string_view str_sub)
1127{
1128 return Sub::IsSub(str, str_sub);
1129}
1130
1131inline bool IsBegin(std::string_view str, std::string_view str_sub)
1132{
1133 return Sub::IsBegin(str, str_sub);
1134}
1135inline std::string_view Range(std::string_view str, char a, char b)
1136{
1137 return Sub::Range(str, a, b);
1138}
1139
1140}
1141
1142}
1143
1144
1145namespace dl
1146{
1147
1148
1149inline std::string to_string(const Vector2<std::string>& vec2)
1150{
1151 return String::Splicing(String::FormatString2(vec2), "\n");
1152}
1153
1154
1155//#if (DL_PLATFORM == DL_PLATFORM_WIN32)
1157//* @brief array的format特化
1158//* @note
1159//*/
1160//template<typename T, size_t N, typename CharT>
1161//struct std::formatter<Array<T, N>, CharT> : std::formatter<std::string, CharT>
1162//{
1163// template <typename FormatParseContext>
1164// auto parse(FormatParseContext& pc)
1165// {
1166// return pc.end();
1167// }
1168//
1169// template<typename FormatContext>
1170// auto format(array<T, N> t, FormatContext& fc)
1171// {
1172// if constexpr (N == 2)
1173// return std::formatter<std::string, CharT>::format(
1174// std::format("{}, {}", t[0], t[1]), fc);
1175// if constexpr (N == 3)
1176// return std::formatter<std::string, CharT>::format(
1177// std::format("{}, {}, {}", t[0], t[1], t[2]), fc);
1178// if constexpr (N == 4)
1179// return std::formatter<std::string, CharT>::format(
1180// std::format("{}, {}, {}, {}", t[0], t[1], t[2], t[3]), fc);
1181// }
1182//};
1183//#endif
1184}
1185
1186
1187
1188
1189
1190namespace fmt
1191{
1192 //
1193 template <typename T>
1194 struct formatter<dl::Array<T, 2>>
1195 {
1196 // 解析格式化参数(这里简化,不处理自定义格式)
1197 constexpr auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin())
1198 {
1199 // 检查是否有多余的格式符
1200 auto it = ctx.begin();
1201 if (it != ctx.end() && *it != '}')
1202 throw fmt::format_error("invalid format specifier for dl::Array<T, 2>");
1203 return it;
1204 }
1205
1206 // 格式化逻辑
1207 template <typename FormatContext>
1208 auto format(const dl::Array<T, 2>& arr, FormatContext& ctx) const -> decltype(ctx.out())
1209 {
1210 return fmt::format_to(ctx.out(), "{}, {}", arr.x, arr.y);
1211 }
1212 };
1213
1214 //
1215 template <typename T>
1216 struct formatter<dl::Array<T, 3>>
1217 {
1218 constexpr auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin())
1219 {
1220 auto it = ctx.begin();
1221 if (it != ctx.end() && *it != '}')
1222 throw fmt::format_error("invalid format specifier for dl::Array<T, 3>");
1223 return it;
1224 }
1225
1226 template <typename FormatContext>
1227 auto format(const dl::Array<T, 3>& arr, FormatContext& ctx) const -> decltype(ctx.out())
1228 {
1229 return fmt::format_to(ctx.out(), "{}, {}, {}", arr.x, arr.y, arr.z);
1230 }
1231 };
1232
1233 //
1234 template <typename T>
1235 struct formatter<dl::Array<T, 4>>
1236 {
1237 constexpr auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin())
1238 {
1239 auto it = ctx.begin();
1240 if (it != ctx.end() && *it != '}')
1241 throw fmt::format_error("invalid format specifier for dl::Array<T, 4>");
1242 return it;
1243 }
1244
1245 template <typename FormatContext>
1246 auto format(const dl::Array<T, 4>& arr, FormatContext& ctx) const -> decltype(ctx.out())
1247 {
1248 return fmt::format_to(ctx.out(), "{}, {}, {}, {}", arr.x, arr.y, arr.z, arr.w);
1249 }
1250 };
1251 //
1252 template <size_t N>
1253 struct formatter<dl::StringN<N>>
1254 {
1255 // 解析格式化参数(这里简化,不处理自定义格式)
1256 constexpr auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin())
1257 {
1258 // 检查是否有多余的格式符
1259 auto it = ctx.begin();
1260 if (it != ctx.end() && *it != '}')
1261 throw fmt::format_error("invalid format specifier for dl::Array<T, 2>");
1262 return it;
1263 }
1264
1265 // 格式化逻辑
1266 template <typename FormatContext>
1267 auto format(const dl::StringN<N>& str, FormatContext& ctx) const -> decltype(ctx.out())
1268 {
1269 return fmt::format_to(ctx.out(), "{}", str.c_str());
1270 }
1271 };
1272}
定长字符串
2维array
表示一段内存
编码转换
日志系统
#define log_warn(...)
范围操作
通用类型定义
2维vector
bool Equal(const C &container, const V &v)
判断容器任意元素等于某值
bool Yes(const C &container, F func)
判断容器任意元素满足条件
std::string Utf32ToUtf8(std::u32string_view str)
字符串转换:utf32 -> utf8
void Match(T &a, const T &b)
从容器a中移除 存在于容器b的元素
bool HeadSub(T &a, const T &b)
移除子串,第一个
bool TailFromLast(T &container, const V &a)
从容器container中移除 最后 匹配到的a元素 之后(不包含a)的所有元素,如果没有匹配到,则什么都不做。
bool HeadFromLast(T &container, const V &a)
从容器container中移除 最后 匹配到的a元素 之前(包含a)的所有元素,如果没有匹配到,则什么都不做。
void Replace(C &c, const V &v, const V &v_new)
替换容器所有元素都等于某值
bool NotEqual(const C &container, const V &v)
判断容器所有元素都 不等于某值
字符串操作
Array< Float, N > toPosition(std::string_view str, char d=',')
字符串 -> Position
bool toBool(std::string_view str, bool default_v=false)
字符串 -> bool
Position toPosition2(std::string_view str, char d=',')
Array< int, N > toPoint(std::string_view str, char d=',')
字符串 -> Point
bool getInt(std::string_view str, int &ret)
转为整数,失败不修改原值
int toInt(std::string_view str, int default_v=0)
转为整数,失败返回设定的默认值
unsigned toUint(std::string_view str, unsigned default_v=0)
constexpr std::string_view GetNotFileName()
返回不能作为文件名的字符
Float toFloat(std::string_view str, Float default_v=0)
字符串 -> Float
bool IsBlank(char ch)
字符串为空白字符,一般意义上( \t空格)
constexpr StringType GetType(std::string_view str)
返回字符串类型
std::vector< std::string_view > ToView(const std::vector< std::string > &a)
转换为 std::vector<std::string_view>
std::string FillEndl(std::string_view str, char ch=' ')
多行文本填充字符至一样宽(控制台显示优化)
std::string AddQuotes(std::string_view str, char quotes='\"')
两侧添加引号
size_t Wcwidth(wchar_t ch)
获取宽字符宽度(控制台显示优化)
std::string_view EraseBlankBoth(std::string_view str)
字符串删除首尾空字符
Point2 toPoint2(std::string_view str, char d=',')
int64_t toInt64(std::string_view str, int64_t default_v=0)
转为整数,失败返回设定的默认值
bool getByte(std::string_view str, std::byte &ret)
转为单个字节,需要十六进制,失败不修改原值
bool IsSub(const T &a, const T &b)
子串匹配
T Range(const T &c, const V &a, const V &b)
区间匹配
bool IsBegin(const T &a, const T &b)
子串匹配
Position2 Position
T r_insert_per_num(const T &container, V v, size_t per_num)
从后面往前,隔n个元素就插入1个值,首尾不会出现分割符
void split_no_empty(const T &container, V delimiter, std::vector< T > &ret)
以 元素 分割 容器
float Float
void split_sub(const T &container, const T &delimiter, std::vector< T > &ret)
以 子串 分割 容器
void log_err0(std::string_view str, DL_SOURCE_LOCATION)
std::string to_string(T v)
to_string包装
void split(const T &container, V delimiter, std::vector< T > &ret)
以 元素 分割 容器
constexpr ArrayS2< T, N > & operator+=(ArrayS2< T, N > &a, const Array< T, 2 > &b)
constexpr ArrayS2< T, N > operator+(const ArrayS2< T, N > &a, const Array< T, 2 > &b)
Array< int, 2 > Point2
std::string to_string_auto(BufferView buf, bool add_tag=false)
buf转为字符串,若不为utf8则转为16进制
std::string to_string_check(BufferView buf, bool tips=true)
buf转为utf8字符串(进行检查)
std::string to_string_hex(BufferView buf, bool upper=false, bool add_tag=false)
buf转为16进制字符串
BufferView CreateBufferView(const Buffer &buf)
创建buffer视图(右值不能默认转换)
std::size_t operator()(std::string_view str) const
std::hash< std::string_view > hash_type
std::size_t operator()(const char *str) const
std::size_t operator()(std::string const &str) const
auto format(const dl::Array< T, 2 > &arr, FormatContext &ctx) const -> decltype(ctx.out())
constexpr auto parse(fmt::format_parse_context &ctx) -> decltype(ctx.begin())
constexpr auto parse(fmt::format_parse_context &ctx) -> decltype(ctx.begin())
auto format(const dl::Array< T, 3 > &arr, FormatContext &ctx) const -> decltype(ctx.out())
constexpr auto parse(fmt::format_parse_context &ctx) -> decltype(ctx.begin())
auto format(const dl::Array< T, 4 > &arr, FormatContext &ctx) const -> decltype(ctx.out())
constexpr auto parse(fmt::format_parse_context &ctx) -> decltype(ctx.begin())
auto format(const dl::StringN< N > &str, FormatContext &ctx) const -> decltype(ctx.out())