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
18namespace fz {
19
32#ifdef FZ_WINDOWS
33typedef std::wstring native_string;
34typedef std::wstring_view native_string_view;
35#endif
36#if defined(FZ_UNIX) || defined(FZ_MAC)
37typedef std::string native_string;
38typedef std::string_view native_string_view;
39#endif
40
45native_string FZ_PUBLIC_SYMBOL to_native(std::string_view const& in);
46
51native_string FZ_PUBLIC_SYMBOL to_native(std::wstring_view const& in);
52
54template<typename T, typename std::enable_if_t<std::is_same_v<native_string, typename std::decay_t<T>>, int> = 0>
55inline native_string to_native(T const& in) {
56 return in;
57}
58
65int FZ_PUBLIC_SYMBOL stricmp(std::string_view const& a, std::string_view const& b);
66int FZ_PUBLIC_SYMBOL stricmp(std::wstring_view const& a, std::wstring_view const& b);
67
85template<typename Char>
86Char tolower_ascii(Char c) {
87 if (c >= 'A' && c <= 'Z') {
88 return c + ('a' - 'A');
89 }
90 return c;
91}
92
93template<>
94std::wstring::value_type FZ_PUBLIC_SYMBOL tolower_ascii(std::wstring::value_type c);
95
97template<typename Char>
98Char toupper_ascii(Char c) {
99 if (c >= 'a' && c <= 'z') {
100 return c + ('A' - 'a');
101 }
102 return c;
103}
104
105template<>
106std::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!
111std::string FZ_PUBLIC_SYMBOL str_tolower_ascii(std::string_view const& s);
112std::wstring FZ_PUBLIC_SYMBOL str_tolower_ascii(std::wstring_view const& s);
113
114std::string FZ_PUBLIC_SYMBOL str_toupper_ascii(std::string_view const& s);
115std::wstring FZ_PUBLIC_SYMBOL str_toupper_ascii(std::wstring_view const& s);
116
122struct 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
138inline 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}
146inline 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
159std::wstring FZ_PUBLIC_SYMBOL to_wstring(std::string_view const& in);
160inline std::wstring FZ_PUBLIC_SYMBOL to_wstring(std::wstring_view const& in) { return std::wstring(in); }
161
166template<typename T, typename std::enable_if_t<std::is_same_v<std::wstring, typename std::decay_t<T>>, int> = 0>
167inline std::wstring to_wstring(T const& in) {
168 return in;
169}
170
172template<typename Arg>
173inline 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
183std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(std::string_view const& in);
184std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(char const* s, size_t len);
185
186class buffer;
187std::wstring FZ_PUBLIC_SYMBOL to_wstring_from_utf8(fz::buffer const& in);
188
193std::string FZ_PUBLIC_SYMBOL to_string(std::wstring_view const& in);
194inline std::string FZ_PUBLIC_SYMBOL to_string(std::string_view const& in) { return std::string(in); }
195
200template<typename T, typename std::enable_if_t<std::is_same_v<std::string, typename std::decay_t<T>>, int> = 0>
201inline std::string to_string(T const& in) {
202 return in;
203}
204
205
207template<typename Arg>
208inline 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
215template<typename Char>
216size_t strlen(Char const* str) {
217 return std::char_traits<Char>::length(str);
218}
219
220
227std::string FZ_PUBLIC_SYMBOL to_utf8(std::string_view const& in);
228
235std::string FZ_PUBLIC_SYMBOL to_utf8(std::wstring_view const& in);
236
238template<typename String, typename Arg>
239inline 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
244template<typename String, typename Arg>
245inline 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
267template<typename Char>
268Char const* choose_string(char const* c, wchar_t const* w);
269
270template<> inline char const* choose_string(char const* c, wchar_t const*) { return c; }
271template<> 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
292std::string FZ_PUBLIC_SYMBOL replaced_substrings(std::string_view const& in, std::string_view const& find, std::string_view const& replacement);
293std::wstring FZ_PUBLIC_SYMBOL replaced_substrings(std::wstring_view const& in, std::wstring_view const& find, std::wstring_view const& replacement);
294
296std::string FZ_PUBLIC_SYMBOL replaced_substrings(std::string_view const& in, char find, char replacement);
297std::wstring FZ_PUBLIC_SYMBOL replaced_substrings(std::wstring_view const& in, wchar_t find, wchar_t replacement);
298
303bool FZ_PUBLIC_SYMBOL replace_substrings(std::string& in, std::string_view const& find, std::string_view const& replacement);
304bool FZ_PUBLIC_SYMBOL replace_substrings(std::wstring& in, std::wstring_view const& find, std::wstring_view const& replacement);
305
307bool FZ_PUBLIC_SYMBOL replace_substrings(std::string& in, char find, char replacement);
308bool FZ_PUBLIC_SYMBOL replace_substrings(std::wstring& in, wchar_t find, wchar_t replacement);
309
316std::vector<std::string> FZ_PUBLIC_SYMBOL strtok(std::string_view const& tokens, std::string_view const& delims, bool const ignore_empty = true);
317std::vector<std::wstring> FZ_PUBLIC_SYMBOL strtok(std::wstring_view const& tokens, std::wstring_view const& delims, bool const ignore_empty = true);
318inline auto FZ_PUBLIC_SYMBOL strtok(std::string_view const& tokens, char const delim, bool const ignore_empty = true) {
319 return strtok(tokens, std::string_view(&delim, 1), ignore_empty);
320}
321inline auto FZ_PUBLIC_SYMBOL strtok(std::wstring_view const& tokens, wchar_t const delim, bool const ignore_empty = true) {
322 return strtok(tokens, std::wstring_view(&delim, 1), ignore_empty);
323}
324
333std::vector<std::string_view> FZ_PUBLIC_SYMBOL strtok_view(std::string_view const& tokens, std::string_view const& delims, bool const ignore_empty = true);
334std::vector<std::wstring_view> FZ_PUBLIC_SYMBOL strtok_view(std::wstring_view const& tokens, std::wstring_view const& delims, bool const ignore_empty = true);
335inline auto FZ_PUBLIC_SYMBOL strtok_view(std::string_view const& tokens, char const delim, bool const ignore_empty = true) {
336 return strtok_view(tokens, std::string_view(&delim, 1), ignore_empty);
337}
338inline auto FZ_PUBLIC_SYMBOL strtok_view(std::wstring_view const& tokens, wchar_t const delim, bool const ignore_empty = true) {
339 return strtok_view(tokens, std::wstring_view(&delim, 1), ignore_empty);
340}
341
343template<typename T, typename String>
344T to_integral_impl(String const& s, T const errorval = T())
345{
346 if constexpr (std::is_same_v<T, bool>) {
347 return static_cast<T>(to_integral_impl<unsigned int>(s, static_cast<unsigned int>(errorval))) != 0;
348 }
349 else if constexpr (std::is_enum_v<T>) {
350 return static_cast<T>(to_integral_impl<std::underlying_type_t<T>>(s, static_cast<std::underlying_type_t<T>>(errorval)));
351 }
352 else {
353 T ret{};
354 auto it = s.cbegin();
355 if (it != s.cend() && (*it == '-' || *it == '+')) {
356 ++it;
357 }
358
359 if (it == s.cend()) {
360 return errorval;
361 }
362
363 for (; it != s.cend(); ++it) {
364 auto const& c = *it;
365 if (c < '0' || c > '9') {
366 return errorval;
367 }
368 ret *= 10;
369 ret += c - '0';
370 }
371
372 if (!s.empty() && s.front() == '-') {
373 ret *= static_cast<T>(-1);
374 }
375 return ret;
376 }
377}
378
380template<typename T>
381T to_integral(std::string_view const& s, T const errorval = T()) {
382 return to_integral_impl<T>(s, errorval);
383}
384
385template<typename T>
386T to_integral(std::wstring_view const& s, T const errorval = T()) {
387 return to_integral_impl<T>(s, errorval);
388}
389
390template<typename T, typename StringType>
391T to_integral(std::basic_string_view<StringType> const& s, T const errorval = T()) {
392 return to_integral_impl<T>(s, errorval);
393}
394
395
397template<typename String>
398bool str_is_ascii(String const& s) {
399 for (auto const& c : s) {
400 if (static_cast<std::make_unsigned_t<typename String::value_type>>(c) > 127) {
401 return false;
402 }
403 }
404
405 return true;
406}
407
409template<typename String, typename Chars>
410void trim_impl(String & s, Chars const& chars, bool fromLeft, bool fromRight) {
411 size_t const first = fromLeft ? s.find_first_not_of(chars) : 0;
412 if (first == String::npos) {
413 s = String();
414 return;
415 }
416
417 size_t const last = fromRight ? s.find_last_not_of(chars) : s.size();
418 if (last == String::npos) {
419 s = String();
420 return;
421 }
422
423 // Invariant: If first exists, then last >= first
424 s = s.substr(first, last - first + 1);
425}
426
428inline std::string FZ_PUBLIC_SYMBOL trimmed(std::string_view s, std::string_view const& chars = " \r\n\t", bool fromLeft = true, bool fromRight = true)
429{
430 trim_impl(s, chars, fromLeft, fromRight);
431 return std::string(s);
432}
433
434inline 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)
435{
436 trim_impl(s, chars, fromLeft, fromRight);
437 return std::wstring(s);
438}
439
440inline std::string FZ_PUBLIC_SYMBOL ltrimmed(std::string_view s, std::string_view const& chars = " \r\n\t")
441{
442 trim_impl(s, chars, true, false);
443 return std::string(s);
444}
445
446inline std::wstring FZ_PUBLIC_SYMBOL ltrimmed(std::wstring_view s, std::wstring_view const& chars = L" \r\n\t")
447{
448 trim_impl(s, chars, true, false);
449 return std::wstring(s);
450}
451
452inline std::string FZ_PUBLIC_SYMBOL rtrimmed(std::string_view s, std::string_view const& chars = " \r\n\t")
453{
454 trim_impl(s, chars, false, true);
455 return std::string(s);
456}
457
458inline std::wstring FZ_PUBLIC_SYMBOL rtrimmed(std::wstring_view s, std::wstring_view const& chars = L" \r\n\t")
459{
460 trim_impl(s, chars, false, true);
461 return std::wstring(s);
462}
463
464
466template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, char>, int> = 0>
467inline void trim(String & s, std::string_view const& chars = " \r\n\t", bool fromLeft = true, bool fromRight = true)
468{
469 trim_impl(s, chars, fromLeft, fromRight);
470}
471
472template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, wchar_t>, int> = 0>
473inline void trim(String & s, std::wstring_view const& chars = L" \r\n\t", bool fromLeft = true, bool fromRight = true)
474{
475 trim_impl(s, chars, fromLeft, fromRight);
476}
477
478template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, char>, int> = 0>
479inline void ltrim(String& s, std::string_view const& chars = " \r\n\t")
480{
481 trim_impl(s, chars, true, false);
482}
483
484template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, wchar_t>, int> = 0>
485inline void ltrim(String& s, std::wstring_view const& chars = L" \r\n\t")
486{
487 trim_impl(s, chars, true, false);
488}
489
490template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, char>, int> = 0>
491inline void rtrim(String& s, std::string_view const& chars = " \r\n\t")
492{
493 trim_impl(s, chars, false, true);
494}
495
496template<typename String, typename std::enable_if_t<std::is_same_v<typename String::value_type, wchar_t>, int> = 0>
497inline void rtrim(String & s, std::wstring_view const& chars = L" \r\n\t")
498{
499 trim_impl(s, chars, false, true);
500}
501
506template<bool insensitive_ascii = false, typename String>
507bool starts_with(String const& s, String const& beginning)
508{
509 if (beginning.size() > s.size()) {
510 return false;
511 }
512 if constexpr (insensitive_ascii) {
513 return std::equal(beginning.begin(), beginning.end(), s.begin(), [](typename String::value_type const& a, typename String::value_type const& b) {
514 return tolower_ascii(a) == tolower_ascii(b);
515 });
516 }
517 else {
518 return std::equal(beginning.begin(), beginning.end(), s.begin());
519 }
520}
521
526template<bool insensitive_ascii = false, typename String>
527bool ends_with(String const& s, String const& ending)
528{
529 if (ending.size() > s.size()) {
530 return false;
531 }
532
533 if constexpr (insensitive_ascii) {
534 return std::equal(ending.rbegin(), ending.rend(), s.rbegin(), [](typename String::value_type const& a, typename String::value_type const& b) {
535 return tolower_ascii(a) == tolower_ascii(b);
536 });
537 }
538 else {
539 return std::equal(ending.rbegin(), ending.rend(), s.rbegin());
540 }
541}
542
548std::string FZ_PUBLIC_SYMBOL normalize_hyphens(std::string_view const& in);
549std::wstring FZ_PUBLIC_SYMBOL normalize_hyphens(std::wstring_view const& in);
550
551}
552
553#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.
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 ends_with(String const &s, String const &ending)
Tests whether the first string ends with the second string.
Definition: string.hpp:527
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:428
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)
Char const * choose_string(char const *c, wchar_t const *w)
Returns the function argument of the type matching the template argument.
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
std::vector< std::string > strtok(std::string_view const &tokens, std::string_view const &delims, bool const ignore_empty=true)
Tokenizes string.
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.
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
int stricmp(std::string_view const &a, std::string_view const &b)
Locale-sensitive stricmp.
std::string str_tolower_ascii(std::string_view const &s)
tr_tolower_ascii does for strings what tolower_ascii does for individual characters
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:467
bool str_is_ascii(String const &s)
Returns true iff the string only has characters in the 7-bit ASCII range.
Definition: string.hpp:398
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:507
std::vector< std::string_view > strtok_view(std::string_view const &tokens, std::string_view const &delims, bool const ignore_empty=true)
Tokenizes string.
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.
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.
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:381
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