Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-string-utils.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
49# ifndef AH_STRING_UTILS_H
50# define AH_STRING_UTILS_H
51
52# include <algorithm>
53# include <array>
54# include <cctype>
55# include <cerrno>
56# include <cmath>
57# include <cstdlib>
58# include <iomanip>
59# include <limits>
60# include <stdexcept>
61# include <string_view>
62# include <type_traits>
63# include <cstring>
64# include <memory>
65# include <string>
66# include <sstream>
67# include <iterator>
68# include <vector>
69# include <htlist.H>
70# include <tpl_array.H>
71# include <ah-zip.H>
72
73namespace Aleph
74{
81 template <typename T>
82 std::string to_string(const std::vector<T> & v)
83 {
84 std::ostringstream s;
85 for (size_t i = 0; i < v.size(); ++i)
86 {
87 s << v[i];
88 if (i < v.size() - 1)
89 s << ", ";
90 }
91 return s.str();
92 }
93
100 template <typename T>
101 std::string to_string(const Array<T> & v)
102 {
103 std::ostringstream s;
104 for (auto it = v.get_it(); it.has_curr(); it.next_ne())
105 {
106 s << it.get_curr();
107 if (not it.is_last())
108 s << ", ";
109 }
110 return s.str();
111 }
112
113 // left trim
120 inline void ltrim(std::string & s)
121 {
122 s.erase(s.begin(), std::find_if(s.begin(), s.end(),
123 [](const unsigned char ch)
124 {
125 return not std::isspace(ch);
126 }));
127 }
128
129 // trim from end
136 inline void rtrim(std::string & s)
137 {
138 s.erase(std::find_if(s.rbegin(), s.rend(),
139 [](const unsigned char ch)
140 {
141 return not std::isspace(ch);
142 }).base(), s.end());
143 }
144
145 namespace concat_detail
146 {
147 template <typename T>
148 inline constexpr bool is_string_like =
149 std::is_convertible_v<T, std::string_view> or
150 std::is_same_v<std::decay_t<T>, char>;
151
152 inline size_t piece_size(std::string_view s) noexcept { return s.size(); }
153 inline size_t piece_size(char) noexcept { return 1; }
154
155 inline void append_to(std::string & out, std::string_view s) { out += s; }
156 inline void append_to(std::string & out, char c) { out += c; }
157
165 template <typename T>
166 std::string stringify(const T & v)
167 {
168 if constexpr (std::is_convertible_v<T, std::string_view>)
169 return std::string(std::string_view(v));
170 else if constexpr (std::is_same_v<std::decay_t<T>, char>)
171 return std::string(1, v);
172 else if constexpr (std::is_arithmetic_v<std::decay_t<T>>)
173 return std::to_string(v);
174 else
175 {
176 std::ostringstream s;
177 s << v;
178 return s.str();
179 }
180 }
181 } // namespace concat_detail
182
198 template <class... Args>
199 inline std::string concat(const Args &... args)
200 {
201 if constexpr (sizeof...(Args) == 0)
202 return {};
203 else if constexpr ((concat_detail::is_string_like<Args> and ...))
204 {
205 std::string result;
206 result.reserve((concat_detail::piece_size(args) + ...));
207 (concat_detail::append_to(result, args), ...);
208 return result;
209 }
210 else
211 {
212 std::array<std::string, sizeof...(Args)> pieces = {
214 };
215 size_t total = 0;
216 for (const auto & p : pieces)
217 total += p.size();
218 std::string result;
219 result.reserve(total);
220 for (const auto & p : pieces)
221 result += p;
222 return result;
223 }
224 }
225
226 // trim from both ends (in place)
232 inline std::string trim(const std::string & s)
233 {
234 std::string ret = s;
235 ltrim(ret);
236 rtrim(ret);
237 return ret;
238 }
239
245 inline std::string &trim_in_place(std::string & s)
246 {
247 ltrim(s);
248 rtrim(s);
249 return s;
250 }
251
258 inline bool contains(const std::string_view & str, const std::string_view & substr)
259 {
260 return str.find(substr) != std::string::npos;
261 }
262
269 inline std::string to_string(const double d, const size_t precision)
270 {
271 std::ostringstream s;
272 s.precision(precision);
273 s << std::fixed << d;
274 return s.str();
275 }
276
284 inline std::string to_str(const double d)
285 {
286 return to_string(d, std::numeric_limits<double>::max_digits10);
287 }
288
294 inline std::string tolower(const char *str)
295 {
296 std::string ret;
297 for (const char *ptr = str; *ptr; ++ptr)
298 ret.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(*ptr))));
299 return ret;
300 }
301
307 inline std::string toupper(const char *str)
308 {
309 std::string ret;
310 for (const char *ptr = str; *ptr; ++ptr)
311 ret.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(*ptr))));
312 return ret;
313 }
314
320 inline std::string tolower(const std::string & str)
321 {
322 return tolower(str.c_str());
323 }
324
330 inline std::string toupper(const std::string & str)
331 {
332 return toupper(str.c_str());
333 }
334
340 inline std::string &mutable_tolower(std::string & str)
341 {
342 for (auto & c: str)
343 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
344 return str;
345 }
346
352 inline std::string &mutable_toupper(std::string & str)
353 {
354 for (auto & c: str)
355 c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
356 return str;
357 }
358
369 inline std::string only_alpha(const std::string & str)
370 {
371 std::string ret;
372 ret.reserve(str.size() + 1);
373 for (const char c: str)
374 switch (c)
375 {
376 case '0'...'9':
377 case 'a'...'z':
378 ret.push_back(c);
379 break;
380 case 'A'...'Z':
381 ret.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
382 break;
383 default:
384 break;
385 }
386
387 return ret;
388 }
389
397 inline std::string remove_spaces(const std::string & str)
398 {
399 const size_t n = str.size();
400 std::string ret;
401 ret.reserve(n + 1);
402 for (const auto c: str)
403 if (not std::isspace(static_cast<unsigned char>(c)))
404 ret.push_back(c);
405 return ret;
406 }
407
414 inline std::string remove_symbols(const std::string & str, const std::string & symbols)
415 {
416 const size_t n = str.size();
417 std::string ret;
418 ret.reserve(n + 1);
419 for (const auto c: str)
420 if (symbols.find(c) == std::string::npos)
421 ret.push_back(c);
422
423 return ret;
424 }
425
437 template <class C>
438 inline std::ostream &join(const C & c, const std::string & sep, std::ostream & out)
439 {
440 if (c.is_empty())
441 return out;
442
443 auto & last = c.get_last();
444 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
445 {
446 auto & curr = it.get_curr();
447 out << curr;
448 if (&curr != &last)
449 out << sep;
450 }
451 return out;
452 }
453
461 template <class C>
462 inline std::string join(const C & c, const std::string & sep = " ")
463 {
464 std::ostringstream s;
465 join(c, sep, s);
466 return s.str();
467 }
468
469 // return true if str can be converted to a double
478 inline bool is_double(const std::string & str)
479 {
480 const char *begin = str.c_str();
481 char *endptr = nullptr;
482 errno = 0;
483 const auto val = std::strtod(begin, &endptr);
484 if (endptr == begin or *endptr != '\0')
485 return false;
486 return errno != ERANGE and std::isfinite(val);
487 }
488
497 inline bool is_float(const std::string & str)
498 {
499 const char *begin = str.c_str();
500 char *endptr = nullptr;
501 errno = 0;
502 const auto val = std::strtof(begin, &endptr);
503 if (endptr == begin or *endptr != '\0')
504 return false;
505 return errno != ERANGE and std::isfinite(val);
506 }
507
516 inline bool is_long(const std::string & str)
517 {
518 const char *begin = str.c_str();
519 char *endptr = nullptr;
520 errno = 0;
521 (void) std::strtol(begin, &endptr, 10);
522 if (endptr == begin or *endptr != '\0')
523 return false;
524 return errno != ERANGE;
525 }
526
535 inline bool is_size_t(const std::string & str)
536 {
537 if (str.empty() or str[0] == '-')
538 return false;
539
540 const char *begin = str.c_str();
541 char *endptr = nullptr;
542 errno = 0;
543 const auto val = std::strtoull(begin, &endptr, 10);
544 if (endptr == begin or *endptr != '\0')
545 return false;
546 if (errno == ERANGE)
547 return false;
549 }
550
551
558 inline long safe_atol(const std::string & s)
559 {
560 errno = 0;
561 char *endptr = nullptr;
562 const auto val = std::strtol(s.c_str(), &endptr, 10);
563 const bool invalid =
564 (errno == ERANGE and (val == LONG_MAX or val == LONG_MIN)) or
565 (errno != 0 and val == 0) or
566 endptr == s.c_str();
567
568 ah_runtime_error_if(invalid) << "invalid std::string for long: " << s;
569 return val;
570 }
571
578 inline double safe_atof(const std::string & s)
579 {
580 errno = 0;
581 char *endptr = nullptr;
582 const auto val = std::strtod(s.c_str(), &endptr);
583 const bool invalid =
584 (errno == ERANGE and (val == HUGE_VAL or val == HUGE_VALF or val == HUGE_VALL)) or
585 (errno != 0 and val == 0) or
586 endptr == s.c_str() or
587 *endptr != '\0' or
588 not std::isfinite(val);
589
590 ah_runtime_error_if(invalid) << "invalid std::string for double: " << s;
591 return val;
592 }
593
600 inline bool is_prefix(const std::string & str, const std::string & prefix)
601 {
602 if (str.size() < prefix.size())
603 return false;
604 return strncmp(str.data(), prefix.data(), prefix.size()) == 0;
605 }
606
613 inline std::string remove_prefix(std::string & str, const std::string & prefix)
614 {
615 if (is_prefix(str, prefix))
616 str = str.substr(prefix.size());
617 return str;
618 }
619
625 inline std::string to_lower(const std::string & str)
626 {
627 std::string ret;
628 for (const char c: str)
629 ret.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
630 return ret;
631 }
632
638 inline std::string to_upper(const std::string & str)
639 {
640 std::string ret;
641 for (const char c: str)
642 ret.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(c))));
643 return ret;
644 }
645
651 inline std::string to_name(const std::string & str)
652 {
653 if (str.empty())
654 return str;
655
656 std::string ret;
657 ret.push_back(static_cast<char>(std::toupper(static_cast<unsigned char>(str[0]))));
658
659 for (size_t i = 1; i < str.size(); ++i)
660 ret.push_back(str[i]);
661
662 return ret;
663 }
664
672 inline DynList<std::string> split_camel_case(const char *const str)
673 {
675 if (str == nullptr or *str == '\0')
676 return ret;
677 const char *ptr = str;
678 std::string curr(1, *ptr);
679 while (*++ptr)
680 if (std::isupper(static_cast<unsigned char>(*ptr)))
681 {
682 ret.append(curr);
683 curr = std::string(1, *ptr);
684 }
685 else
686 curr.push_back(*ptr);
687
688 if (not curr.empty())
689 ret.append(curr);
690
691 return ret;
692 }
693
699 inline DynList<std::string> split_camel_case(const std::string & str)
700 {
701 return split_camel_case(str.data());
702 }
703
709 inline void fill_string(std::string & str, char sym)
710 {
711 for (char & c: str)
712 c = sym;
713 }
714
724 inline std::vector<std::string> &
725 split(const std::string & s, const char delim, std::vector<std::string> & elems)
726 {
727 std::stringstream ss(s);
728 std::string item;
729 while (getline(ss, item, delim))
730 elems.push_back(item);
731
732 return elems;
733 }
734
741 inline std::vector<std::string> split(const std::string & s, const char delim)
742 {
743 std::vector<std::string> elems;
744 split(s, delim, elems);
745 return elems;
746 }
747
759 template <template <typename> class Container = DynList>
760 inline Container<std::string> split_string(const std::string & s, const std::string & delim)
761 {
763 if (s.empty())
764 return elems;
765
766 if (delim.empty())
767 {
768 elems.append(s);
769 return elems;
770 }
771
772 char *saveptr = nullptr;
773 char **p = &saveptr;
774
775 std::string data = s;
776 const char *d = delim.data();
777 const auto str = data.data();
778
779 for (char *token = strtok_r(str, d, p); token;
780 token = strtok_r(nullptr, d, p))
781 elems.append(token);
782
783 return elems;
784 }
785
792 inline DynList<std::string> split_to_list(const std::string & s,
793 const std::string & delim)
794 {
795 return split_string<DynList>(s, delim);
796 }
797
806 inline std::string to_Pascalcase(const std::string & str)
807 {
809
810 tokens.mutable_for_each([](std::string & token)
811 {
812 token[0] = ::toupper(token[0]);
813 });
814
815 return tokens.foldl<std::string>("", [](const std::string & acu, const std::string & token)
816 {
817 return acu + token;
818 });
819 }
820
827 inline Array<std::string> split_to_array(const std::string & s,
828 const std::string & delim)
829 {
830 return split_string<Array>(s, delim);
831 }
832
840 inline std::pair<std::string, std::string> split_pos(const std::string & str, const size_t pos)
841 {
842 ah_range_error_if(pos > str.size())
843 << "split_pos(" << str << ", " << pos << "): position " << pos
844 << " is larger than std::string size " << str.size();
845
846
847 const char *ptr = str.data();
848 const char *end1 = ptr + pos;
849
850 std::string s1;
851 while (ptr != end1)
852 s1.push_back(*ptr++);
853
854 std::string s2;
855 while (*ptr)
856 s2.push_back(*ptr++);
857
858 return {s1, s2};
859 }
860
871 inline DynList<std::string> split_n(const std::string & str, const size_t n)
872 {
873 ah_range_error_if(n == 0) << "split_n(): number of parts cannot be 0";
874
875 ah_range_error_if(n > str.size())
876 << "split_n(" << str << ", " << n << "): number of parts " << n
877 << " is larger than std::string size " << str.size();
878
879 const size_t sz = str.size() / n;
880
881 const char *ptr = str.data();
882
884
885 for (size_t i = 0; i < n; ++i)
886 {
887 std::string s;
888 if (i + 1 == n)
889 while (*ptr)
890 s.push_back(*ptr++);
891 else
892 for (size_t k = 0; k < sz and *ptr; ++k)
893 s.push_back(*ptr++);
894
895 ret.append(s);
896 }
897
898 return ret;
899 }
900
910 template <typename T>
912 {
913 size_t max_sz = 0;
914 DynList<size_t> sizes =
915 m.template maps<size_t>([&max_sz](auto & l)
916 {
917 const size_t sz = l.size();
918 max_sz = std::max(max_sz, sz);
919 return sz;
920 });
921
923 for (auto it = zip_it(m, sizes); it.has_curr(); it.next_ne())
924 {
925 auto t = it.get_curr();
926 DynList<T> & l = get<0>(t);
927 const size_t sz = get<1>(t);
928 const long n = max_sz - sz;
929 for (auto i = 0; i < n; ++i)
930 l.append(T());
931 ret.append(std::move(l));
932 }
933
934 return ret;
935 }
936
944 const DynList<DynList<std::string>> & mat)
945 {
946 return mat.maps<DynList<std::string>>([&lens](const DynList<std::string> & l)
947 {
948 return zip(lens, l).template maps<std::string>([](const auto & p)
949 {
950 const std::string blanks(p.first > p.second.size() ?
951 p.first - p.second.size() :
952 0, ' ');
953 return blanks + p.second + " ";
954 });
955 });
956 }
957
965 inline std::ostream &format_string(std::ostream & out, const DynList<size_t> & lens,
966 const DynList<DynList<std::string>> & mat)
967 {
968 for (auto it = mat.get_it(); it.has_curr(); it.next_ne())
969 {
970 const auto & row = it.get_curr();
971 auto line = zip(lens, row).
972 template maps<std::string>([](const auto & p)
973 {
974 const std::string blanks(p.first > p.second.size() ?
975 p.first - p.second.size() :
976 0, ' ');
977 return blanks + p.second + " ";
978 });
979 line.for_each([&out](const auto & s)
980 {
981 out << s;
982 });
983 out << '\n';
984 }
985
986 return out;
987 }
988
996 {
997 if (mat.is_empty())
998 return mat;
999
1000 const DynList<size_t> ilens = rep<size_t>(mat.nth(0).size(), 0);
1001 const DynList<size_t> maxs =
1002 mat.foldl(ilens, [](const DynList<size_t> & acu,
1003 const DynList<std::string> & l)
1004 {
1005 return zip(acu, l).
1006 maps<size_t>([](const auto & p)
1007 {
1008 return std::max(p.first, p.second.size());
1009 });
1010 });
1011
1012 return format_string(maxs, mat);
1013 }
1014
1022 {
1024 for (auto row_it = mat.get_it(); row_it.has_curr(); row_it.next_ne())
1025 {
1026 const DynList<std::string> & curr_row = row_it.get_curr();
1027 const std::string & last = curr_row.get_last();
1029 for (auto it = curr_row.get_it(); it.has_curr(); it.next_ne())
1030 {
1031 const std::string & s = it.get_curr();
1032 if (&s == &last)
1033 row.append(s);
1034 else
1035 row.append(s + ",");
1036 }
1037 ret.append(row);
1038 }
1039
1040 return ret;
1041 }
1042
1050 inline std::string to_string(const DynList<DynList<std::string>> & mat)
1051 {
1052 std::ostringstream s;
1053 mat.for_each([&s](const auto & row)
1054 {
1055 row.for_each([&s](const std::string & str)
1056 {
1057 s << str;
1058 });
1059 s << '\n';
1060 });
1061 return s.str();
1062 }
1063
1070 {
1072 std::istringstream in(text);
1073 for (std::string word; in >> word;)
1074 words.append(word);
1075 return words;
1076 }
1077
1084 {
1085 return split_to_list(text, "\n");
1086 }
1087
1093 inline std::string to_string(const DynList<std::string> & lines)
1094 {
1095 std::ostringstream s;
1096 for (auto it = lines.get_it(); it.has_curr(); it.next_ne())
1097 {
1098 const auto & line = it.get_curr();
1099 s << line;
1100 if (line != lines.get_last())
1101 s << '\n';
1102 }
1103
1104 return s.str();
1105 }
1106
1113 inline std::string justify_line(std::string line, const size_t page_width)
1114 {
1115 if (size_t pos = line.find_first_of(' '); pos != std::string::npos)
1116 while (line.size() < page_width)
1117 {
1118 pos = line.find_first_not_of(' ', pos);
1119 if (pos == std::string::npos)
1120 break;
1121 line.insert(pos, " ");
1122 pos = line.find_first_of(' ', pos + 1);
1123 if (pos == std::string::npos)
1124 pos = line.find_first_of(' ');
1125 }
1126
1127 return line;
1128 }
1129
1137 inline std::string justify_text(const std::string & text,
1138 const size_t width,
1139 const size_t left_margin = 0)
1140 {
1141 auto words = split_text_into_words(text);
1142
1143 std::ostringstream s;
1144 std::string line;
1145 for (const std::string & word: words)
1146 if (line.size() + word.size() + 1 > width)
1147 {
1148 // next word doesn't fit into the line
1149 if (not line.empty())
1150 {
1151 s << std::string(left_margin, ' ') << justify_line(line, width) << '\n';
1152 line.clear();
1153 }
1154 line = word;
1155 }
1156 else
1157 {
1158 if (not line.empty())
1159 line.append(" ");
1160 line.append(word);
1161 }
1162
1163 s << std::string(left_margin, ' ') << line;
1164
1165 return s.str();
1166 }
1167
1175 inline std::string justify_line_except_first(const std::string & text,
1176 const size_t width,
1177 const size_t left_margin = 0)
1178 {
1179 const auto formatted = justify_text(text, width);
1181 std::ostringstream s;
1182 s << lines.remove_first() << '\n';
1183 s << justify_text(to_string(lines), width, left_margin);
1184 return s.str();
1185 }
1186
1194 inline std::string align_text_to_left(const std::string & text,
1195 const size_t page_width,
1196 const size_t left_margin = 0)
1197 {
1198 auto words = split_text_into_words(text);
1199
1200 const std::string margin(left_margin, ' ');
1201 std::ostringstream s;
1202 std::string line;
1203 for (const std::string & word: words)
1204 if (line.size() + word.size() + 1 > page_width)
1205 {
1206 // next word doesn't fit into the line
1207 if (not line.empty())
1208 {
1209 s << margin << line << '\n';
1210 line.clear();
1211 }
1212 line = word;
1213 }
1214 else
1215 {
1216 if (not line.empty())
1217 line.append(" ");
1218 line.append(word);
1219 }
1220
1221 s << margin << line;
1222
1223 return s.str();
1224 }
1225
1233 inline std::string align_text_to_left_except_first(const std::string & text,
1234 const size_t width,
1235 const size_t left_margin = 0)
1236 {
1237 const auto formatted = align_text_to_left(text, width);
1239 std::ostringstream s;
1240 s << lines.remove_first() << '\n';
1242 return s.str();
1243 }
1244
1251 inline std::string shift_lines_to_left(const std::string & str, const size_t n)
1252 {
1253 std::ostringstream s;
1254 const std::string fill(n, ' ');
1255 const auto lines = split_to_list(str, "\n");
1256 for (auto it = lines.get_it(); it.has_curr(); it.next_ne())
1257 {
1258 const auto & line = it.get_curr();
1259 s << fill << line;
1260 if (line != lines.get_last())
1261 s << '\n';
1262 }
1263 return s.str();
1264 }
1265
1270 inline void build_pars_list(std::string & unused)
1271 {
1272 (void) unused;
1273 }
1274
1275 template <typename T>
1276 requires requires(std::ostream & out, const T & v)
1277 {
1278 out << v;
1279 }
1280
1287 inline void build_pars_list(std::string & str, const T & item)
1288 {
1289 std::ostringstream s;
1290 if (not str.empty())
1291 s << ", ";
1292 s << item;
1293 str.append(s.str());
1294 }
1295
1304 template <class T, class... Args>
1305 inline void build_pars_list(std::string & str, const T & item, Args... args)
1306 {
1307 build_pars_list(str, item);
1308 build_pars_list(str, args...);
1309 }
1310
1314 template <class First, class... Rest>
1315 requires (not requires(const std::remove_reference_t<First> & c)
1316 {
1317 c.is_empty();
1318 c.get_last();
1319 c.get_it();
1320 })
1331 inline std::string build_pars_list(const First & first, const Rest &... rest)
1332 {
1333 std::string ret;
1334 build_pars_list(ret, first, rest...);
1335 return ret;
1336 }
1337
1338 template <class C>
1339 requires requires(const C & c)
1340 {
1341 c.is_empty();
1342 c.get_last();
1343 c.get_it();
1344 }
1352 inline std::string build_pars_list(const C & c, const std::string & sep = ",")
1353 {
1354 if (c.is_empty())
1355 return "";
1356
1357 auto & last = c.get_last();
1358 std::ostringstream s;
1359 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1360 {
1361 auto & curr = it.get_curr();
1362 s << curr;
1363 if (&curr != &last)
1364 s << sep;
1365 }
1366 return s.str();
1367 }
1368}
1369
1370# endif // AH_STRING_UTILS_H
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:266
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:207
Zip iterators and functional operations for multiple containers.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
T & get_last() const
Return the last item of the list.
Definition htlist.H:1363
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
__T foldl(const __T &init, Op &op) const
Fold the elements of the container to a specific result.
Definition ah-dry.H:1200
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:779
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:1057
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
Singly linked list implementations with head-tail access.
size_t piece_size(std::string_view s) noexcept
std::string stringify(const T &v)
Convert any single value to std::string.
constexpr bool is_string_like
void append_to(std::string &out, std::string_view s)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::string tolower(const char *str)
Convert a C std::string to lower-case.
ZipIterator< Cs... > zip_it(const Cs &...cs)
Alias for get_zip_it.
Definition ah-zip.H:270
bool is_prefix(const std::string &str, const std::string &prefix)
Check whether prefix is a prefix of str.
std::string remove_symbols(const std::string &str, const std::string &symbols)
Remove any character appearing in symbols.
std::string to_upper(const std::string &str)
Convert a std::string to upper-case (byte-wise).
DynList< std::string > split_text_into_lines(const std::string &text)
Split a text into lines by "\n".
std::string justify_line_except_first(const std::string &text, const size_t width, const size_t left_margin=0)
Justify all lines except the first one.
DynList< std::string > split_text_into_words(const std::string &text)
Split a text into whitespace-separated words.
Array< std::string > split_to_array(const std::string &s, const std::string &delim)
Split a std::string into an Aleph::Array<std::string>.
std::pair< std::string, std::string > split_pos(const std::string &str, const size_t pos)
Split a std::string at a fixed position.
long safe_atol(const std::string &s)
Convert a std::string to long and throw on parse errors.
void ltrim(std::string &s)
Remove leading whitespace from a std::string in-place.
std::string remove_prefix(std::string &str, const std::string &prefix)
Remove prefix from str if present.
std::string & trim_in_place(std::string &s)
Trim a std::string in-place (leading + trailing whitespace removed).
std::string align_text_to_left(const std::string &text, const size_t page_width, const size_t left_margin=0)
Align text to the left by wrapping lines at page_width.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip(const Container1 &a, const Container2 &b)
Zip two containers into a list of pairs.
void fill(Itor beg, const Itor &end, const T &value)
Fill a range with a value.
Definition ahAlgo.H:707
Container< std::string > split_string(const std::string &s, const std::string &delim)
Split a std::string by a set of delimiter characters.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
bool contains(const std::string_view &str, const std::string_view &substr)
Check if substr appears inside str.
std::string justify_line(std::string line, const size_t page_width)
Justify a single line by inserting extra spaces.
std::string to_Pascalcase(const std::string &str)
Convert an identifier-like std::string to PascalCase.
DynList< DynList< std::string > > format_string_csv(const DynList< DynList< std::string > > &mat)
Produce a CSV-like matrix (commas added to all but last element in each row).
static void prefix(Node *root, DynList< Node * > &acc)
bool is_long(const std::string &str)
Check whether a std::string fully parses as a long.
DynList< std::string > split_n(const std::string &str, const size_t n)
Split a std::string into n parts.
std::string to_name(const std::string &str)
Uppercase the first character of str and return the resulting copy.
bool is_float(const std::string &str)
Check whether a std::string fully parses as a finite float.
bool is_size_t(const std::string &str)
Check whether a std::string fully parses as a non-negative size_t.
std::string trim(const std::string &s)
Return a trimmed copy of a std::string (leading + trailing whitespace removed).
DynList< std::string > split_camel_case(const char *const str)
Split a camelCase / PascalCase std::string into tokens.
void build_pars_list(std::string &unused)
Base case for build_pars_list(std::string&, ...).
std::string remove_spaces(const std::string &str)
Remove all whitespace characters from a std::string.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
std::string to_str(const double d)
Convert double to a std::string with maximum round-trip precision.
std::string justify_text(const std::string &text, const size_t width, const size_t left_margin=0)
Justify a text to a target width.
bool is_double(const std::string &str)
Check whether a std::string fully parses as a finite double.
DynList< std::string > split_to_list(const std::string &s, const std::string &delim)
Split a std::string into an Aleph::DynList<std::string>.
std::string shift_lines_to_left(const std::string &str, const size_t n)
Indent every line in a multi-line std::string by n spaces.
std::string concat(const Args &... args)
Concatenate multiple arguments into a single std::string.
DynList< DynList< T > > complete_rows(DynList< DynList< T > > &m)
Pad all rows of a matrix to the maximum row length.
std::string align_text_to_left_except_first(const std::string &text, const size_t width, const size_t left_margin=0)
Align all lines except the first one.
std::string toupper(const char *str)
Convert a C std::string to upper-case.
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
void rtrim(std::string &s)
Remove trailing whitespace from a std::string in-place.
std::vector< std::string > & split(const std::string &s, const char delim, std::vector< std::string > &elems)
Split a std::string by a single delimiter character.
DynList< DynList< std::string > > format_string(const DynList< size_t > &lens, const DynList< DynList< std::string > > &mat)
double safe_atof(const std::string &s)
Convert a std::string to double and throw on parse errors.
std::string to_lower(const std::string &str)
Convert a std::string to lower-case (byte-wise).
void fill_string(std::string &str, char sym)
Fill all the content of std::string with a defined char.
std::string & mutable_tolower(std::string &str)
Convert a std::string to lower-case in-place.
std::string & mutable_toupper(std::string &str)
Convert a std::string to upper-case in-place.
std::string only_alpha(const std::string &str)
Extract alphanumeric ASCII characters and normalize letters to lower-case.
FooMap m(5, fst_unit_pair_hash, snd_unit_pair_hash)
static int * k
Dynamic array container with automatic resizing.
DynList< int > l