libfilezilla
string.hpp
Go to the documentation of this file.
1 #ifndef LIBFILEZILLA_STRING_HEADER
2 #define LIBFILEZILLA_STRING_HEADER
3 
4 #include "libfilezilla.hpp"
5 
6 #include <algorithm>
7 #include <string>
8 #include <string_view>
9 #include <vector>
10 
18 namespace fz {
19 
32 #ifdef FZ_WINDOWS
33 typedef std::wstring native_string;
34 typedef std::wstring_view native_string_view;
35 #endif
36 #if defined(FZ_UNIX) || defined(FZ_MAC)
37 typedef std::string native_string;
38 typedef std::string_view native_string_view;
39 #endif
40 
45 native_string FZ_PUBLIC_SYMBOL to_native(std::string_view const& in);
46 
51 native_string FZ_PUBLIC_SYMBOL to_native(std::wstring_view const& in);
52 
54 template<typename T, typename std::enable_if_t<std::is_same_v<native_string, typename std::decay_t<T>>, int> = 0>
55 inline native_string to_native(T const& in) {
56  return in;
57 }
58 
65 int FZ_PUBLIC_SYMBOL stricmp(std::string_view const& a, std::string_view const& b);
66 int FZ_PUBLIC_SYMBOL stricmp(std::wstring_view const& a, std::wstring_view const& b);
67 
85 template<typename Char>
86 Char tolower_ascii(Char c) {
87  if (c >= 'A' && c <= 'Z') {
88  return c + ('a' - 'A');
89  }
90  return c;
91 }
92 
93 template<>
94 std::wstring::value_type FZ_PUBLIC_SYMBOL tolower_ascii(std::wstring::value_type c);
95 
97 template<typename Char>
98 Char toupper_ascii(Char c) {
99  if (c >= 'a' && c <= 'z') {
100  return c + ('A' - 'a');
101  }
102  return c;
103 }
104 
105 template<>
106 std::wstring::value_type FZ_PUBLIC_SYMBOL toupper_ascii(std::wstring::value_type c);
107 
110  // Note: For UTF-8 strings it works on individual octets!
111 std::string FZ_PUBLIC_SYMBOL str_tolower_ascii(std::string_view const& s);
112 std::wstring FZ_PUBLIC_SYMBOL str_tolower_ascii(std::wstring_view const& s);
113 
114 std::string FZ_PUBLIC_SYMBOL str_toupper_ascii(std::string_view const& s);
115 std::wstring FZ_PUBLIC_SYMBOL str_toupper_ascii(std::wstring_view const& s);
116 
122 struct FZ_PUBLIC_SYMBOL less_insensitive_ascii final
123 {
124  template<typename T>
125  bool operator()(T const& lhs, T const& rhs) const {
126  return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(),
127  [](typename T::value_type const& a, typename T::value_type const& b) {
128  return tolower_ascii(a) < tolower_ascii(b);
129  }
130  );
131  }
132 };
133 
138 inline bool equal_insensitive_ascii(std::string_view a, std::string_view b)
139 {
140  return std::equal(a.cbegin(), a.cend(), b.cbegin(), b.cend(),
141  [](auto const& a, auto const& b) {
142  return tolower_ascii(a) == tolower_ascii(b);
143  }
144  );
145 }
146 inline bool equal_insensitive_ascii(std::wstring_view a, std::wstring_view b)
147 {
148  return std::equal(a.cbegin(), a.cend(), b.cbegin(), b.cend(),
149  [](auto const& a, auto const& b) {
150  return tolower_ascii(a) == tolower_ascii(b);
151  }
152  );
153 }
154 
159 std::wstring FZ_PUBLIC_SYMBOL to_wstring(std::string_view const& in);
160 inline std::wstring FZ_PUBLIC_SYMBOL to_wstring(std::wstring_view const& in) { return std::wstring(in); }
161 
166 template<typename T, typename std::enable_if_t<std::is_same_v<std::wstring, typename std::decay_t<T>>, int> = 0>
167 inline std::wstring to_wstring(T const& in) {
168  return in;
169 }
170 
172 template<typename Arg>
173 inline typename std::enable_if<std::is_arithmetic_v<std::decay_t<Arg>>, std::wstring>::type to_wstring(Arg && arg)
174 {
175  return std::to_wstring(std::forward<Arg>(arg));
176 }
177 
178 
183 std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(std::string_view const& in);
184 std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(char const* s, size_t len);
185 
186 class buffer;
187 std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(fz::buffer const& in);
188 
193 std::string FZ_PUBLIC_SYMBOL to_string(std::wstring_view const& in);
194 inline std::string FZ_PUBLIC_SYMBOL to_string(std::string_view const& in) { return std::string(in); }
195 
200 template<typename T, typename std::enable_if_t<std::is_same_v<std::string, typename std::decay_t<T>>, int> = 0>
201 inline std::string to_string(T const& in) {
202  return in;
203 }
204 
205 
207 template<typename Arg>
208 inline typename std::enable_if<std::is_arithmetic_v<std::decay_t<Arg>>, std::string>::type to_string(Arg && arg)
209 {
210  return std::to_string(std::forward<Arg>(arg));
211 }
212 
213 
215 template<typename Char>
216 size_t strlen(Char const* str) {
217  return std::char_traits<Char>::length(str);
218 }
219 
220 
227 std::string FZ_PUBLIC_SYMBOL to_utf8(std::string_view const& in);
228 
235 std::string FZ_PUBLIC_SYMBOL to_utf8(std::wstring_view const& in);
236 
238 template<typename String, typename Arg>
239 inline auto toString(Arg&& arg) -> typename std::enable_if<std::is_same_v<String, std::string>, decltype(to_string(std::forward<Arg>(arg)))>::type
240 {
241  return to_string(std::forward<Arg>(arg));
242 }
243 
244 template<typename String, typename Arg>
245 inline auto toString(Arg&& arg) -> typename std::enable_if<std::is_same_v<String, std::wstring>, decltype(to_wstring(std::forward<Arg>(arg)))>::type
246 {
247  return to_wstring(std::forward<Arg>(arg));
248 }
249 
250 #if !defined(fzT) || defined(DOXYGEN)
251 #ifdef FZ_WINDOWS
256 #define fzT(x) L ## x
257 #else
262 #define fzT(x) x
263 #endif
264 #endif
265 
267 template<typename Char>
268 Char const* choose_string(char const* c, wchar_t const* w);
269 
270 template<> inline char const* choose_string(char const* c, wchar_t const*) { return c; }
271 template<> inline wchar_t const* choose_string(char const*, wchar_t const* w) { return w; }
272 
273 #if !defined(fzS) || defined(DOXYGEN)
285 #define fzS(Char, s) fz::choose_string<Char>(s, L ## s)
286 #endif
287 
289 std::string FZ_PUBLIC_SYMBOL replaced_substrings(std::string_view const& in, std::string_view const& find, std::string_view const& replacement);
290 std::wstring FZ_PUBLIC_SYMBOL replaced_substrings(std::wstring_view const& in, std::wstring_view const& find, std::wstring_view const& replacement);
291 std::string FZ_PUBLIC_SYMBOL replaced_substrings(std::string_view const& in, char find, char replacement);
292 std::wstring FZ_PUBLIC_SYMBOL replaced_substrings(std::wstring_view const& in, wchar_t find, wchar_t replacement);
293 
295 bool FZ_PUBLIC_SYMBOL replace_substrings(std::string& in, std::string_view const& find, std::string_view const& replacement);
296 bool FZ_PUBLIC_SYMBOL replace_substrings(std::wstring& in, std::wstring_view const& find, std::wstring_view const& replacement);
297 bool FZ_PUBLIC_SYMBOL replace_substrings(std::string& in, char find, char replacement);
298 bool FZ_PUBLIC_SYMBOL replace_substrings(std::wstring& in, wchar_t find, wchar_t replacement);
299 
306 std::vector<std::string> FZ_PUBLIC_SYMBOL strtok(std::string_view const& tokens, std::string_view const& delims, bool const ignore_empty = true);
307 std::vector<std::wstring> FZ_PUBLIC_SYMBOL strtok(std::wstring_view const& tokens, std::wstring_view const& delims, bool const ignore_empty = true);
308 inline auto FZ_PUBLIC_SYMBOL strtok(std::string_view const& tokens, char const delim, bool const ignore_empty = true) {
309  return strtok(tokens, std::string_view(&delim, 1), ignore_empty);
310 }
311 inline auto FZ_PUBLIC_SYMBOL strtok(std::wstring_view const& tokens, wchar_t const delim, bool const ignore_empty = true) {
312  return strtok(tokens, std::wstring_view(&delim, 1), ignore_empty);
313 }
314 
323 std::vector<std::string_view> FZ_PUBLIC_SYMBOL strtok_view(std::string_view const& tokens, std::string_view const& delims, bool const ignore_empty = true);
324 std::vector<std::wstring_view> FZ_PUBLIC_SYMBOL strtok_view(std::wstring_view const& tokens, std::wstring_view const& delims, bool const ignore_empty = true);
325 inline auto FZ_PUBLIC_SYMBOL strtok_view(std::string_view const& tokens, char const delim, bool const ignore_empty = true) {
326  return strtok_view(tokens, std::string_view(&delim, 1), ignore_empty);
327 }
328 inline auto FZ_PUBLIC_SYMBOL strtok_view(std::wstring_view const& tokens, wchar_t const delim, bool const ignore_empty = true) {
329  return strtok_view(tokens, std::wstring_view(&delim, 1), ignore_empty);
330 }
331 
333 template<typename T, typename String>
334 T to_integral_impl(String const& s, T const errorval = T())
335 {
336  if constexpr (std::is_same_v<T, bool>) {
337  return static_cast<T>(to_integral_impl<unsigned int>(s, static_cast<unsigned int>(errorval))) != 0;
338  }
339  else if constexpr (std::is_enum_v<T>) {
340  return static_cast<T>(to_integral_impl<std::underlying_type_t<T>>(s, static_cast<std::underlying_type_t<T>>(errorval)));
341  }
342  else {
343  T ret{};
344  auto it = s.cbegin();
345  if (it != s.cend() && (*it == '-' || *it == '+')) {
346  ++it;
347  }
348 
349  if (it == s.cend()) {
350  return errorval;
351  }
352 
353  for (; it != s.cend(); ++it) {
354  auto const& c = *it;
355  if (c < '0' || c > '9') {
356  return errorval;
357  }
358  ret *= 10;
359  ret += c - '0';
360  }
361 
362  if (!s.empty() && s.front() == '-') {
363  ret *= static_cast<T>(-1);
364  }
365  return ret;
366  }
367 }
368 
370 template<typename T>
371 T to_integral(std::string_view const& s, T const errorval = T()) {
372  return to_integral_impl<T>(s, errorval);
373 }
374 
375 template<typename T>
376 T to_integral(std::wstring_view const& s, T const errorval = T()) {
377  return to_integral_impl<T>(s, errorval);
378 }
379 
380 template<typename T, typename StringType>
381 T to_integral(std::basic_string_view<StringType> const& s, T const errorval = T()) {
382  return to_integral_impl<T>(s, errorval);
383 }
384 
385 
387 template<typename String>
388 bool str_is_ascii(String const& s) {
389  for (auto const& c : s) {
390  if (static_cast<std::make_unsigned_t<typename String::value_type>>(c) > 127) {
391  return false;
392  }
393  }
394 
395  return true;
396 }
397 
399 template<typename String, typename Chars>
400 void trim_impl(String & s, Chars const& chars, bool fromLeft, bool fromRight) {
401  size_t const first = fromLeft ? s.find_first_not_of(chars) : 0;
402  if (first == String::npos) {
403  s = String();
404  return;
405  }
406 
407  size_t const last = fromRight ? s.find_last_not_of(chars) : s.size();
408  if (last == String::npos) {
409  s = String();
410  return;
411  }
412 
413  // Invariant: If first exists, then last >= first
414  s = s.substr(first, last - first + 1);
415 }
416 
418 inline std::string FZ_PUBLIC_SYMBOL trimmed(std::string_view s, std::string_view const& chars = " \r\n\t", bool fromLeft = true, bool fromRight = true)
419 {
420  trim_impl(s, chars, fromLeft, fromRight);
421  return std::string(s);
422 }
423 
424 inline std::wstring FZ_PUBLIC_SYMBOL trimmed(std::wstring_view s, std::wstring_view const& chars = L" \r\n\t", bool fromLeft = true, bool fromRight = true)
425 {
426  trim_impl(s, chars, fromLeft, fromRight);
427  return std::wstring(s);
428 }
429 
430 inline std::string FZ_PUBLIC_SYMBOL ltrimmed(std::string_view s, std::string_view const& chars = " \r\n\t")
431 {
432  trim_impl(s, chars, true, false);
433  return std::string(s);
434 }
435 
436 inline std::wstring FZ_PUBLIC_SYMBOL ltrimmed(std::wstring_view s, std::wstring_view const& chars = L" \r\n\t")
437 {
438  trim_impl(s, chars, true, false);
439  return std::wstring(s);
440 }
441 
442 inline std::string FZ_PUBLIC_SYMBOL rtrimmed(std::string_view s, std::string_view const& chars = " \r\n\t")
443 {
444  trim_impl(s, chars, false, true);
445  return std::string(s);
446 }
447 
448 inline std::wstring FZ_PUBLIC_SYMBOL rtrimmed(std::wstring_view s, std::wstring_view const& chars = L" \r\n\t")
449 {
450  trim_impl(s, chars, false, true);
451  return std::wstring(s);
452 }
453 
454 
456 template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, char>, int> = 0>
457 inline void trim(String & s, std::string_view const& chars = " \r\n\t", bool fromLeft = true, bool fromRight = true)
458 {
459  trim_impl(s, chars, fromLeft, fromRight);
460 }
461 
462 template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, wchar_t>, int> = 0>
463 inline void trim(String & s, std::wstring_view const& chars = L" \r\n\t", bool fromLeft = true, bool fromRight = true)
464 {
465  trim_impl(s, chars, fromLeft, fromRight);
466 }
467 
468 template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, char>, int> = 0>
469 inline void ltrim(String& s, std::string_view const& chars = " \r\n\t")
470 {
471  trim_impl(s, chars, true, false);
472 }
473 
474 template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, wchar_t>, int> = 0>
475 inline void ltrim(String& s, std::wstring_view const& chars = L" \r\n\t")
476 {
477  trim_impl(s, chars, true, false);
478 }
479 
480 template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, char>, int> = 0>
481 inline void rtrim(String& s, std::string_view const& chars = " \r\n\t")
482 {
483  trim_impl(s, chars, false, true);
484 }
485 
486 template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, wchar_t>, int> = 0>
487 inline void rtrim(String & s, std::wstring_view const& chars = L" \r\n\t")
488 {
489  trim_impl(s, chars, false, true);
490 }
491 
496 template<bool insensitive_ascii = false, typename String>
497 bool starts_with(String const& s, String const& beginning)
498 {
499  if (beginning.size() > s.size()) {
500  return false;
501  }
502  if constexpr (insensitive_ascii) {
503  return std::equal(beginning.begin(), beginning.end(), s.begin(), [](typename String::value_type const& a, typename String::value_type const& b) {
504  return tolower_ascii(a) == tolower_ascii(b);
505  });
506  }
507  else {
508  return std::equal(beginning.begin(), beginning.end(), s.begin());
509  }
510 }
511 
516 template<bool insensitive_ascii = false, typename String>
517 bool ends_with(String const& s, String const& ending)
518 {
519  if (ending.size() > s.size()) {
520  return false;
521  }
522 
523  if constexpr (insensitive_ascii) {
524  return std::equal(ending.rbegin(), ending.rend(), s.rbegin(), [](typename String::value_type const& a, typename String::value_type const& b) {
525  return tolower_ascii(a) == tolower_ascii(b);
526  });
527  }
528  else {
529  return std::equal(ending.rbegin(), ending.rend(), s.rbegin());
530  }
531 }
532 
538 std::string FZ_PUBLIC_SYMBOL normalize_hyphens(std::string_view const& in);
539 std::wstring FZ_PUBLIC_SYMBOL normalize_hyphens(std::wstring_view const& in);
540 
541 }
542 
543 #endif
The buffer class is a simple buffer where data can be appended at the end and consumed at the front....
Definition: buffer.hpp:26
Sets some global macros and further includes string.hpp.
The namespace used by libfilezilla.
Definition: apply.hpp:17
std::wstring to_wstring_from_utf8(std::string_view const &in)
Converts from std::string in UTF-8 into std::wstring.
Char const * choose_string(char const *c, wchar_t const *w)
Returns the function argument of the type matching the template argument.
Definition: string.hpp:270
bool ends_with(String const &s, String const &ending)
Tests whether the first string ends with the second string.
Definition: string.hpp:517
Char toupper_ascii(Char c)
Converts ASCII lowercase characters to uppercase as if C-locale is used.
Definition: string.hpp:98
std::string trimmed(std::string_view s, std::string_view const &chars=" \r\n\t", bool fromLeft=true, bool fromRight=true)
Return passed string with all leading and trailing whitespace removed.
Definition: string.hpp:418
auto toString(Arg &&arg) -> typename std::enable_if< std::is_same_v< String, std::string >, decltype(to_string(std::forward< Arg >(arg)))>::type
Calls either fz::to_string or fz::to_wstring depending on the passed template argument.
Definition: string.hpp:239
std::string normalize_hyphens(std::string_view const &in)
std::wstring to_wstring(std::string_view const &in)
Converts from std::string in system encoding into std::wstring.
Char tolower_ascii(Char c)
Converts ASCII uppercase characters to lowercase as if C-locale is used.
Definition: string.hpp:86
size_t strlen(Char const *str)
Returns length of 0-terminated character sequence. Works with both narrow and wide-characters.
Definition: string.hpp:216
std::wstring native_string
A string in the system's native character type and encoding. Note: This typedef changes depending on...
Definition: string.hpp:33
std::string replaced_substrings(std::string_view const &in, std::string_view const &find, std::string_view const &replacement)
Returns in with all occurrences of find in the input string replaced with replacement.
int stricmp(std::string_view const &a, std::string_view const &b)
Locale-sensitive stricmp.
std::vector< std::string_view > strtok_view(std::string_view const &tokens, std::string_view const &delims, bool const ignore_empty=true)
Tokenizes string.
std::string str_tolower_ascii(std::string_view const &s)
tr_tolower_ascii does for strings what tolower_ascii does for individual characters
std::enable_if< std::is_arithmetic_v< std::decay_t< Arg > >, std::string >::type to_string(Arg &&arg)
Converts from arithmetic type to std::string.
Definition: string.hpp:208
void trim(String &s, std::string_view const &chars=" \r\n\t", bool fromLeft=true, bool fromRight=true)
Remove all leading and trailing whitespace from string.
Definition: string.hpp:457
bool str_is_ascii(String const &s)
Returns true iff the string only has characters in the 7-bit ASCII range.
Definition: string.hpp:388
std::string to_string(std::wstring_view const &in)
Converts from std::wstring into std::string in system encoding.
bool starts_with(String const &s, String const &beginning)
Tests whether the first string starts with the second string.
Definition: string.hpp:497
bool equal_insensitive_ascii(std::string_view a, std::string_view b)
Locale-insensitive stricmp.
Definition: string.hpp:138
std::string to_utf8(std::string_view const &in)
Converts from std::string in native encoding into std::string in UTF-8.
std::enable_if< std::is_arithmetic_v< std::decay_t< Arg > >, std::wstring >::type to_wstring(Arg &&arg)
Converts from arithmetic type to std::wstring.
Definition: string.hpp:173
bool replace_substrings(std::string &in, std::string_view const &find, std::string_view const &replacement)
Modifies in, replacing all occurrences of find with replacement.
std::vector< std::string > strtok(std::string_view const &tokens, std::string_view const &delims, bool const ignore_empty=true)
Tokenizes string.
T to_integral(std::string_view const &s, T const errorval=T())
Converts string to integral type T. If string is not convertible, errorval is returned.
Definition: string.hpp:371
native_string to_native(std::string_view const &in)
Converts std::string to native_string.
Comparator to be used for std::map for case-insensitive keys.
Definition: string.hpp:123