5#ifndef BITCOIN_UTIL_STRING_H
6#define BITCOIN_UTIL_STRING_H
22template <
unsigned num_params>
25 unsigned count_normal{0};
26 unsigned count_pos{0};
27 for (
auto it{str}; *it !=
'\0'; ++it) {
28 if (*it !=
'%' || *++it ==
'%')
continue;
31 unsigned maybe_num{0};
32 while (
'0' <= *it && *it <=
'9') {
34 maybe_num += *it -
'0';
41 if (maybe_num == 0)
throw "Positional format specifier must have position of at least 1";
42 count_pos = std::max(count_pos, maybe_num);
53 while (*it ==
'#' || *it ==
'0' || *it ==
'-' || *it ==
' ' || *it ==
'+') ++it;
55 auto parse_size = [&] {
60 while (
'0' <= *it && *it <=
'9') ++it;
73 if (*it ==
'\0')
throw "Format specifier incorrectly terminated by end of string";
78 if (count_normal && count_pos)
throw "Format specifiers must be all positional or all non-positional!";
79 unsigned count{count_normal | count_pos};
80 if (num_params !=
count)
throw "Format specifier count must match the argument count!";
92template <
unsigned num_params>
94 const char*
const fmt;
98void ReplaceAll(std::string& in_out,
const std::string& search,
const std::string& substitute);
115template <
typename T = std::span<const
char>>
116std::vector<T>
Split(
const std::span<const char>& sp, std::string_view separators,
bool include_sep =
false)
119 auto it = sp.begin();
121 while (it != sp.end()) {
122 if (separators.find(*it) != std::string::npos) {
124 ret.emplace_back(start, it + 1);
126 ret.emplace_back(start, it);
132 ret.emplace_back(start, it);
143template <
typename T = std::span<const
char>>
144std::vector<T>
Split(
const std::span<const char>& sp,
char sep,
bool include_sep =
false)
146 return Split<T>(sp, std::string_view{&sep, 1}, include_sep);
149[[nodiscard]]
inline std::vector<std::string>
SplitString(std::string_view str,
char sep)
151 return Split<std::string>(str, sep);
154[[nodiscard]]
inline std::vector<std::string>
SplitString(std::string_view str, std::string_view separators)
156 return Split<std::string>(str, separators);
159[[nodiscard]]
inline std::string_view
TrimStringView(std::string_view str, std::string_view pattern =
" \f\n\r\t\v")
161 std::string::size_type front = str.find_first_not_of(pattern);
162 if (front == std::string::npos) {
165 std::string::size_type end = str.find_last_not_of(pattern);
166 return str.substr(front, end - front + 1);
169[[nodiscard]]
inline std::string
TrimString(std::string_view str, std::string_view pattern =
" \f\n\r\t\v")
174[[nodiscard]]
inline std::string_view
RemoveSuffixView(std::string_view str, std::string_view suffix)
176 if (str.ends_with(suffix)) {
177 return str.substr(0, str.size() - suffix.size());
184 if (str.starts_with(
prefix)) {
185 return str.substr(
prefix.size());
203template <
typename C,
typename S,
typename UnaryOp>
205auto Join(
const C& container,
const S& separator, UnaryOp unary_op)
207 decltype(unary_op(*container.begin()))
ret;
209 for (
const auto& item : container) {
210 if (!first)
ret += separator;
211 ret += unary_op(item);
217template <
typename C,
typename S>
218auto Join(
const C& container,
const S& separator)
220 return Join(container, separator, [](
const auto& i) {
return i; });
228 return Join(items,
"\n", [](
const std::string& item) {
return "- " + item; });
237 if (c == 0)
return false;
248 std::ostringstream oss;
249 oss.imbue(std::locale::classic());
257template <
typename T1,
size_t PREFIX_LEN>
259 const std::array<uint8_t, PREFIX_LEN>&
prefix)
261 return obj.size() >= PREFIX_LEN &&
262 std::equal(std::begin(
prefix), std::end(
prefix), std::begin(obj));
266 const std::span<const std::byte>::iterator
start;
267 const std::span<const std::byte>::iterator
end;
269 std::span<const std::byte>::iterator
it;
281 std::optional<std::string>
ReadLine();
static constexpr void CheckNumFormatSpecifiers(const char *str)
std::vector< std::string > SplitString(std::string_view str, char sep)
bool HasPrefix(const T1 &obj, const std::array< uint8_t, PREFIX_LEN > &prefix)
Check whether a container begins with the given prefix.
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
std::string RemovePrefix(std::string_view str, std::string_view prefix)
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
bool ContainsNoNUL(std::string_view str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
void ReplaceAll(std::string &in_out, const std::string &search, const std::string &substitute)
std::vector< T > Split(const std::span< const char > &sp, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
size_t Remaining() const
Returns remaining size of bytes in buffer.
std::span< conststd::byte >::iterator it
LineReader(std::span< const std::byte > buffer, size_t max_line_length)
const std::span< conststd::byte >::iterator end
std::string ReadLength(size_t len)
Returns string from current iterator position of specified length if possible and advances iterator o...
const size_t max_line_length
const std::span< conststd::byte >::iterator start
std::optional< std::string > ReadLine()
Returns a string from current iterator position up to (but not including) next and advances iterator...