49# ifndef AH_STRING_UTILS_H
50# define AH_STRING_UTILS_H
61# include <string_view>
62# include <type_traits>
85 for (
size_t i = 0; i < v.size(); ++i)
100 template <
typename T>
103 std::ostringstream s;
104 for (
auto it = v.
get_it(); it.has_curr(); it.next_ne())
107 if (
not it.is_last())
122 s.erase(s.begin(), std::find_if(s.begin(), s.end(),
123 [](
const unsigned char ch)
125 return not std::isspace(ch);
138 s.erase(std::find_if(s.rbegin(), s.rend(),
139 [](
const unsigned char ch)
141 return not std::isspace(ch);
145 namespace concat_detail
147 template <
typename T>
149 std::is_convertible_v<T, std::string_view>
or
150 std::is_same_v<std::decay_t<T>,
char>;
152 inline size_t piece_size(std::string_view s)
noexcept {
return s.size(); }
165 template <
typename T>
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);
176 std::ostringstream s;
198 template <
class...
Args>
201 if constexpr (
sizeof...(Args) == 0)
203 else if constexpr ((concat_detail::is_string_like<Args>
and ...))
212 std::array<std::string,
sizeof...(Args)>
pieces = {
216 for (
const auto & p :
pieces)
219 result.reserve(
total);
220 for (
const auto & p :
pieces)
232 inline std::string
trim(
const std::string & s)
258 inline bool contains(
const std::string_view & str,
const std::string_view &
substr)
260 return str.find(
substr) != std::string::npos;
269 inline std::string
to_string(
const double d,
const size_t precision)
271 std::ostringstream s;
272 s.precision(precision);
273 s << std::fixed << d;
284 inline std::string
to_str(
const double d)
286 return to_string(d, std::numeric_limits<double>::max_digits10);
297 for (
const char *ptr = str; *ptr; ++ptr)
298 ret.push_back(
static_cast<char>(std::tolower(
static_cast<unsigned char>(*ptr))));
310 for (
const char *ptr = str; *ptr; ++ptr)
311 ret.push_back(
static_cast<char>(std::toupper(
static_cast<unsigned char>(*ptr))));
320 inline std::string
tolower(
const std::string & str)
330 inline std::string
toupper(
const std::string & str)
343 c =
static_cast<char>(std::tolower(
static_cast<unsigned char>(c)));
355 c =
static_cast<char>(std::toupper(
static_cast<unsigned char>(c)));
372 ret.reserve(str.size() + 1);
373 for (
const char c: str)
381 ret.push_back(
static_cast<char>(std::tolower(
static_cast<unsigned char>(c))));
399 const size_t n = str.size();
402 for (
const auto c: str)
403 if (
not std::isspace(
static_cast<unsigned char>(c)))
416 const size_t n = str.size();
419 for (
const auto c: str)
420 if (
symbols.find(c) == std::string::npos)
438 inline std::ostream &
join(
const C & c,
const std::string &
sep, std::ostream &
out)
443 auto & last = c.get_last();
444 for (
auto it = c.get_it(); it.has_curr(); it.next_ne())
446 auto & curr = it.get_curr();
462 inline std::string
join(
const C & c,
const std::string &
sep =
" ")
464 std::ostringstream s;
480 const char *begin = str.c_str();
483 const auto val = std::strtod(begin, &
endptr);
499 const char *begin = str.c_str();
502 const auto val = std::strtof(begin, &
endptr);
518 const char *begin = str.c_str();
537 if (str.empty()
or str[0] ==
'-')
540 const char *begin = str.c_str();
543 const auto val = std::strtoull(begin, &
endptr, 10);
562 const auto val = std::strtol(s.c_str(), &
endptr, 10);
582 const auto val = std::strtod(s.c_str(), &
endptr);
588 not std::isfinite(val);
602 if (str.size() <
prefix.size())
616 str = str.substr(
prefix.size());
625 inline std::string
to_lower(
const std::string & str)
628 for (
const char c: str)
629 ret.push_back(
static_cast<char>(std::tolower(
static_cast<unsigned char>(c))));
638 inline std::string
to_upper(
const std::string & str)
641 for (
const char c: str)
642 ret.push_back(
static_cast<char>(std::toupper(
static_cast<unsigned char>(c))));
651 inline std::string
to_name(
const std::string & str)
657 ret.push_back(
static_cast<char>(std::toupper(
static_cast<unsigned char>(str[0]))));
659 for (
size_t i = 1; i < str.size(); ++i)
660 ret.push_back(str[i]);
675 if (str ==
nullptr or *str ==
'\0')
677 const char *ptr = str;
678 std::string curr(1, *ptr);
680 if (std::isupper(
static_cast<unsigned char>(*ptr)))
683 curr = std::string(1, *ptr);
686 curr.push_back(*ptr);
688 if (
not curr.empty())
724 inline std::vector<std::string> &
727 std::stringstream
ss(s);
730 elems.push_back(item);
741 inline std::vector<std::string>
split(
const std::string & s,
const char delim)
743 std::vector<std::string>
elems;
775 std::string data = s;
776 const char *d =
delim.data();
777 const auto str = data.data();
779 for (
char *token =
strtok_r(str, d, p); token;
793 const std::string &
delim)
810 tokens.mutable_for_each([](std::string & token)
815 return tokens.foldl<std::string>(
"", [](
const std::string &
acu,
const std::string & token)
828 const std::string &
delim)
840 inline std::pair<std::string, std::string>
split_pos(
const std::string & str,
const size_t pos)
843 <<
"split_pos(" << str <<
", " << pos <<
"): position " << pos
844 <<
" is larger than std::string size " << str.size();
847 const char *ptr = str.data();
848 const char *
end1 = ptr + pos;
852 s1.push_back(*ptr++);
856 s2.push_back(*ptr++);
876 <<
"split_n(" << str <<
", " << n <<
"): number of parts " << n
877 <<
" is larger than std::string size " << str.
size();
879 const size_t sz = str.size() / n;
881 const char *ptr = str.data();
885 for (
size_t i = 0; i < n; ++i)
892 for (
size_t k = 0;
k < sz
and *ptr; ++
k)
910 template <
typename T>
917 const size_t sz =
l.
size();
923 for (
auto it =
zip_it(
m, sizes); it.has_curr(); it.next_ne())
925 auto t = it.get_curr();
927 const size_t sz =
get<1>(t);
928 const long n =
max_sz - sz;
929 for (
auto i = 0; i < n; ++i)
931 ret.append(std::move(
l));
950 const std::string
blanks(p.first > p.second.size() ?
951 p.first - p.second.size() :
953 return blanks + p.second +
" ";
968 for (
auto it = mat.get_it(); it.has_curr(); it.next_ne())
970 const auto & row = it.get_curr();
971 auto line =
zip(lens, row).
974 const std::string
blanks(p.first > p.second.size() ?
975 p.first - p.second.size() :
977 return blanks + p.second +
" ";
1008 return std::max(p.first, p.second.size());
1029 for (
auto it =
curr_row.get_it(); it.has_curr(); it.next_ne())
1031 const std::string & s = it.get_curr();
1052 std::ostringstream s;
1053 mat.for_each([&s](
const auto & row)
1055 row.for_each([&s](
const std::string & str)
1072 std::istringstream
in(
text);
1095 std::ostringstream s;
1096 for (
auto it =
lines.get_it(); it.has_curr(); it.next_ne())
1098 const auto & line = it.get_curr();
1100 if (line !=
lines.get_last())
1115 if (
size_t pos = line.find_first_of(
' '); pos != std::string::npos)
1118 pos = line.find_first_not_of(
' ', pos);
1119 if (pos == std::string::npos)
1121 line.insert(pos,
" ");
1122 pos = line.find_first_of(
' ', pos + 1);
1123 if (pos == std::string::npos)
1124 pos = line.find_first_of(
' ');
1143 std::ostringstream s;
1145 for (
const std::string &
word: words)
1146 if (line.size() +
word.size() + 1 > width)
1149 if (
not line.empty())
1158 if (
not line.empty())
1181 std::ostringstream s;
1182 s <<
lines.remove_first() <<
'\n';
1201 std::ostringstream s;
1203 for (
const std::string &
word: words)
1207 if (
not line.empty())
1209 s <<
margin << line <<
'\n';
1216 if (
not line.empty())
1239 std::ostringstream s;
1240 s <<
lines.remove_first() <<
'\n';
1253 std::ostringstream s;
1254 const std::string
fill(n,
' ');
1256 for (
auto it =
lines.get_it(); it.has_curr(); it.next_ne())
1258 const auto & line = it.get_curr();
1260 if (line !=
lines.get_last())
1275 template <
typename T>
1276 requires requires(std::ostream &
out,
const T & v)
1289 std::ostringstream s;
1290 if (
not str.empty())
1293 str.append(s.str());
1304 template <
class T,
class...
Args>
1314 template <
class First,
class...
Rest>
1315 requires (
not requires(
const std::remove_reference_t<First> & c)
1339 requires requires(
const C & c)
1357 auto & last = c.get_last();
1358 std::ostringstream s;
1359 for (
auto it = c.get_it(); it.has_curr(); it.next_ne())
1361 auto & curr = it.get_curr();
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Zip iterators and functional operations for multiple containers.
Simple dynamic array with automatic resizing and functional operations.
Dynamic singly linked list with functional programming support.
T & append(const T &item)
T & get_last() const
Return the last item of the list.
size_t size() const noexcept
Count the number of elements of the list.
__T foldl(const __T &init, Op &op) const
Fold the elements of the container to a specific result.
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
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.
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.
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.
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
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.
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)
Dynamic array container with automatic resizing.