Bitcoin Core  29.1.0
P2P Digital Currency
string.h
Go to the documentation of this file.
1 // Copyright (c) 2019-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_UTIL_STRING_H
6 #define BITCOIN_UTIL_STRING_H
7 
8 #include <span.h>
9 
10 #include <array>
11 #include <cstdint>
12 #include <cstring>
13 #include <locale>
14 #include <sstream>
15 #include <string> // IWYU pragma: export
16 #include <string_view> // IWYU pragma: export
17 #include <vector>
18 
19 namespace util {
20 namespace detail {
21 template <unsigned num_params>
22 constexpr static void CheckNumFormatSpecifiers(const char* str)
23 {
24  unsigned count_normal{0}; // Number of "normal" specifiers, like %s
25  unsigned count_pos{0}; // Max number in positional specifier, like %8$s
26  for (auto it{str}; *it != '\0'; ++it) {
27  if (*it != '%' || *++it == '%') continue; // Skip escaped %%
28 
29  auto add_arg = [&] {
30  unsigned maybe_num{0};
31  while ('0' <= *it && *it <= '9') {
32  maybe_num *= 10;
33  maybe_num += *it - '0';
34  ++it;
35  }
36 
37  if (*it == '$') {
38  ++it;
39  // Positional specifier, like %8$s
40  if (maybe_num == 0) throw "Positional format specifier must have position of at least 1";
41  count_pos = std::max(count_pos, maybe_num);
42  } else {
43  // Non-positional specifier, like %s
44  ++count_normal;
45  }
46  };
47 
48  // Increase argument count and consume positional specifier, if present.
49  add_arg();
50 
51  // Consume flags.
52  while (*it == '#' || *it == '0' || *it == '-' || *it == ' ' || *it == '+') ++it;
53 
54  auto parse_size = [&] {
55  if (*it == '*') {
56  ++it;
57  add_arg();
58  } else {
59  while ('0' <= *it && *it <= '9') ++it;
60  }
61  };
62 
63  // Consume dynamic or static width value.
64  parse_size();
65 
66  // Consume dynamic or static precision value.
67  if (*it == '.') {
68  ++it;
69  parse_size();
70  }
71 
72  if (*it == '\0') throw "Format specifier incorrectly terminated by end of string";
73 
74  // Length and type in "[flags][width][.precision][length]type"
75  // is not checked. Parsing continues with the next '%'.
76  }
77  if (count_normal && count_pos) throw "Format specifiers must be all positional or all non-positional!";
78  unsigned count{count_normal | count_pos};
79  if (num_params != count) throw "Format specifier count must match the argument count!";
80 }
81 } // namespace detail
82 
91 template <unsigned num_params>
93  const char* const fmt;
94  consteval ConstevalFormatString(const char* str) : fmt{str} { detail::CheckNumFormatSpecifiers<num_params>(fmt); }
95 };
96 
97 void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
98 
106 template <typename T = Span<const char>>
107 std::vector<T> Split(const Span<const char>& sp, std::string_view separators)
108 {
109  std::vector<T> ret;
110  auto it = sp.begin();
111  auto start = it;
112  while (it != sp.end()) {
113  if (separators.find(*it) != std::string::npos) {
114  ret.emplace_back(start, it);
115  start = it + 1;
116  }
117  ++it;
118  }
119  ret.emplace_back(start, it);
120  return ret;
121 }
122 
130 template <typename T = Span<const char>>
131 std::vector<T> Split(const Span<const char>& sp, char sep)
132 {
133  return Split<T>(sp, std::string_view{&sep, 1});
134 }
135 
136 [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
137 {
138  return Split<std::string>(str, sep);
139 }
140 
141 [[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, std::string_view separators)
142 {
143  return Split<std::string>(str, separators);
144 }
145 
146 [[nodiscard]] inline std::string_view TrimStringView(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
147 {
148  std::string::size_type front = str.find_first_not_of(pattern);
149  if (front == std::string::npos) {
150  return {};
151  }
152  std::string::size_type end = str.find_last_not_of(pattern);
153  return str.substr(front, end - front + 1);
154 }
155 
156 [[nodiscard]] inline std::string TrimString(std::string_view str, std::string_view pattern = " \f\n\r\t\v")
157 {
158  return std::string(TrimStringView(str, pattern));
159 }
160 
161 [[nodiscard]] inline std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
162 {
163  if (str.ends_with(suffix)) {
164  return str.substr(0, str.size() - suffix.size());
165  }
166  return str;
167 }
168 
169 [[nodiscard]] inline std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
170 {
171  if (str.substr(0, prefix.size()) == prefix) {
172  return str.substr(prefix.size());
173  }
174  return str;
175 }
176 
177 [[nodiscard]] inline std::string RemovePrefix(std::string_view str, std::string_view prefix)
178 {
179  return std::string(RemovePrefixView(str, prefix));
180 }
181 
190 template <typename C, typename S, typename UnaryOp>
191 // NOLINTNEXTLINE(misc-no-recursion)
192 auto Join(const C& container, const S& separator, UnaryOp unary_op)
193 {
194  decltype(unary_op(*container.begin())) ret;
195  bool first{true};
196  for (const auto& item : container) {
197  if (!first) ret += separator;
198  ret += unary_op(item);
199  first = false;
200  }
201  return ret;
202 }
203 
204 template <typename C, typename S>
205 auto Join(const C& container, const S& separator)
206 {
207  return Join(container, separator, [](const auto& i) { return i; });
208 }
209 
213 inline std::string MakeUnorderedList(const std::vector<std::string>& items)
214 {
215  return Join(items, "\n", [](const std::string& item) { return "- " + item; });
216 }
217 
221 [[nodiscard]] inline bool ContainsNoNUL(std::string_view str) noexcept
222 {
223  for (auto c : str) {
224  if (c == 0) return false;
225  }
226  return true;
227 }
228 
232 template <typename T>
233 std::string ToString(const T& t)
234 {
235  std::ostringstream oss;
236  oss.imbue(std::locale::classic());
237  oss << t;
238  return oss.str();
239 }
240 
244 template <typename T1, size_t PREFIX_LEN>
245 [[nodiscard]] inline bool HasPrefix(const T1& obj,
246  const std::array<uint8_t, PREFIX_LEN>& prefix)
247 {
248  return obj.size() >= PREFIX_LEN &&
249  std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
250 }
251 } // namespace util
252 
253 #endif // BITCOIN_UTIL_STRING_H
void ReplaceAll(std::string &in_out, const std::string &search, const std::string &substitute)
Definition: string.cpp:11
int ret
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:136
std::string TrimString(std::string_view str, std::string_view pattern=" \\\)
Definition: string.h:156
constexpr C * end() const noexcept
Definition: span.h:176
const char * prefix
Definition: rest.cpp:1009
static constexpr void CheckNumFormatSpecifiers(const char *str)
Definition: string.h:22
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
Definition: string.h:161
std::string RemovePrefix(std::string_view str, std::string_view prefix)
Definition: string.h:177
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
bool ContainsNoNUL(std::string_view str) noexcept
Check if a string does not contain any embedded NUL (\0) characters.
Definition: string.h:221
std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
Definition: string.h:169
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \\\)
Definition: string.h:146
consteval ConstevalFormatString(const char *str)
Definition: string.h:94
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:213
const char *const fmt
Definition: string.h:93
bool HasPrefix(const T1 &obj, const std::array< uint8_t, PREFIX_LEN > &prefix)
Check whether a container begins with the given prefix.
Definition: string.h:245
A wrapper for a compile-time partially validated format string.
Definition: string.h:92
std::vector< T > Split(const Span< const char > &sp, std::string_view separators)
Split a string on any char found in separators, returning a vector.
Definition: string.h:107
constexpr C * begin() const noexcept
Definition: span.h:175
static int count
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:97
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition: string.h:192
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:233