kodi
StringUtils.h
1 /*
2  * Copyright (C) 2005-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 //-----------------------------------------------------------------------
12 //
13 // File: StringUtils.h
14 //
15 // Purpose: ATL split string utility
16 // Author: Paul J. Weiss
17 //
18 // Modified to support J O'Leary's std::string class by kraqh3d
19 //
20 //------------------------------------------------------------------------
21 
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <string>
25 #include <vector>
26 #include <sstream>
27 #include <locale>
28 
29 // workaround for broken [[deprecated]] in coverity
30 #if defined(__COVERITY__)
31 #undef FMT_DEPRECATED
32 #define FMT_DEPRECATED
33 #endif
34 #include "utils/TimeFormat.h"
35 #include "utils/params_check_macros.h"
36 
37 #include <fmt/format.h>
38 #if FMT_VERSION >= 80000
39 #include <fmt/xchar.h>
40 #endif
41 
55 #define DEF_TO_STR_NAME(x) #x
56 #define DEF_TO_STR_VALUE(x) DEF_TO_STR_NAME(x)
57 
58 template<typename T, std::enable_if_t<!std::is_enum<T>::value, int> = 0>
59 constexpr auto&& EnumToInt(T&& arg) noexcept
60 {
61  return arg;
62 }
63 template<typename T, std::enable_if_t<std::is_enum<T>::value, int> = 0>
64 constexpr auto EnumToInt(T&& arg) noexcept
65 {
66  return static_cast<int>(arg);
67 }
68 
70 {
71 public:
78  template<typename... Args>
79  static std::string Format(const std::string& fmt, Args&&... args)
80  {
81  // coverity[fun_call_w_exception : FALSE]
82  return ::fmt::format(fmt, EnumToInt(std::forward<Args>(args))...);
83  }
84  template<typename... Args>
85  static std::wstring Format(const std::wstring& fmt, Args&&... args)
86  {
87  // coverity[fun_call_w_exception : FALSE]
88  return ::fmt::format(fmt, EnumToInt(std::forward<Args>(args))...);
89  }
90 
91  static std::string FormatV(PRINTF_FORMAT_STRING const char *fmt, va_list args);
92  static std::wstring FormatV(PRINTF_FORMAT_STRING const wchar_t *fmt, va_list args);
93  static std::string ToUpper(const std::string& str);
94  static std::wstring ToUpper(const std::wstring& str);
95  static void ToUpper(std::string &str);
96  static void ToUpper(std::wstring &str);
97  static std::string ToLower(const std::string& str);
98  static std::wstring ToLower(const std::wstring& str);
99  static void ToLower(std::string &str);
100  static void ToLower(std::wstring &str);
101  static void ToCapitalize(std::string &str);
102  static void ToCapitalize(std::wstring &str);
103  static bool EqualsNoCase(const std::string &str1, const std::string &str2);
104  static bool EqualsNoCase(const std::string &str1, const char *s2);
105  static bool EqualsNoCase(const char *s1, const char *s2);
106  static int CompareNoCase(const std::string& str1, const std::string& str2, size_t n = 0);
107  static int CompareNoCase(const char* s1, const char* s2, size_t n = 0);
108  static int ReturnDigits(const std::string &str);
109  static std::string Left(const std::string &str, size_t count);
110  static std::string Mid(const std::string &str, size_t first, size_t count = std::string::npos);
111  static std::string Right(const std::string &str, size_t count);
112  static std::string& Trim(std::string &str);
113  static std::string& Trim(std::string &str, const char* const chars);
114  static std::string& TrimLeft(std::string &str);
115  static std::string& TrimLeft(std::string &str, const char* const chars);
116  static std::string& TrimRight(std::string &str);
117  static std::string& TrimRight(std::string &str, const char* const chars);
118  static std::string& RemoveDuplicatedSpacesAndTabs(std::string& str);
119 
126  static bool IsSpecialCharacter(char c);
127 
128  static std::string ReplaceSpecialCharactersWithSpace(const std::string& str);
129  static int Replace(std::string &str, char oldChar, char newChar);
130  static int Replace(std::string &str, const std::string &oldStr, const std::string &newStr);
131  static int Replace(std::wstring &str, const std::wstring &oldStr, const std::wstring &newStr);
132  static bool StartsWith(const std::string &str1, const std::string &str2);
133  static bool StartsWith(const std::string &str1, const char *s2);
134  static bool StartsWith(const char *s1, const char *s2);
135  static bool StartsWithNoCase(const std::string &str1, const std::string &str2);
136  static bool StartsWithNoCase(const std::string &str1, const char *s2);
137  static bool StartsWithNoCase(const char *s1, const char *s2);
138  static bool EndsWith(const std::string &str1, const std::string &str2);
139  static bool EndsWith(const std::string &str1, const char *s2);
140  static bool EndsWithNoCase(const std::string &str1, const std::string &str2);
141  static bool EndsWithNoCase(const std::string &str1, const char *s2);
142 
143  template<typename CONTAINER>
144  static std::string Join(const CONTAINER &strings, const std::string& delimiter)
145  {
146  std::string result;
147  for (const auto& str : strings)
148  result += str + delimiter;
149 
150  if (!result.empty())
151  result.erase(result.size() - delimiter.size());
152  return result;
153  }
154 
164  static std::vector<std::string> Split(const std::string& input, const std::string& delimiter, unsigned int iMaxStrings = 0);
165  static std::vector<std::string> Split(const std::string& input, const char delimiter, size_t iMaxStrings = 0);
166  static std::vector<std::string> Split(const std::string& input, const std::vector<std::string> &delimiters);
178  template<typename OutputIt>
179  static OutputIt SplitTo(OutputIt d_first, const std::string& input, const std::string& delimiter, unsigned int iMaxStrings = 0)
180  {
181  OutputIt dest = d_first;
182 
183  if (input.empty())
184  return dest;
185  if (delimiter.empty())
186  {
187  *d_first++ = input;
188  return dest;
189  }
190 
191  const size_t delimLen = delimiter.length();
192  size_t nextDelim;
193  size_t textPos = 0;
194  do
195  {
196  if (--iMaxStrings == 0)
197  {
198  *dest++ = input.substr(textPos);
199  break;
200  }
201  nextDelim = input.find(delimiter, textPos);
202  *dest++ = input.substr(textPos, nextDelim - textPos);
203  textPos = nextDelim + delimLen;
204  } while (nextDelim != std::string::npos);
205 
206  return dest;
207  }
208  template<typename OutputIt>
209  static OutputIt SplitTo(OutputIt d_first, const std::string& input, const char delimiter, size_t iMaxStrings = 0)
210  {
211  return SplitTo(d_first, input, std::string(1, delimiter), iMaxStrings);
212  }
213  template<typename OutputIt>
214  static OutputIt SplitTo(OutputIt d_first, const std::string& input, const std::vector<std::string> &delimiters)
215  {
216  OutputIt dest = d_first;
217  if (input.empty())
218  return dest;
219 
220  if (delimiters.empty())
221  {
222  *dest++ = input;
223  return dest;
224  }
225  std::string str = input;
226  for (size_t di = 1; di < delimiters.size(); di++)
227  StringUtils::Replace(str, delimiters[di], delimiters[0]);
228  return SplitTo(dest, str, delimiters[0]);
229  }
230 
245  static std::vector<std::string> SplitMulti(const std::vector<std::string>& input,
246  const std::vector<std::string>& delimiters,
247  size_t iMaxStrings = 0);
248  static int FindNumber(const std::string& strInput, const std::string &strFind);
249  static int64_t AlphaNumericCompare(const wchar_t *left, const wchar_t *right);
250  static int AlphaNumericCollation(int nKey1, const void* pKey1, int nKey2, const void* pKey2);
251  static long TimeStringToSeconds(const std::string &timeString);
252  static void RemoveCRLF(std::string& strLine);
253 
258  static size_t utf8_strlen(const char *s);
259 
266  static std::string SecondsToTimeString(long seconds, TIME_FORMAT format = TIME_FORMAT_GUESS);
267 
273  static bool IsNaturalNumber(const std::string& str);
274 
280  static bool IsInteger(const std::string& str);
281 
282  /* The next several isasciiXX and asciiXXvalue functions are locale independent (US-ASCII only),
283  * as opposed to standard ::isXX (::isalpha, ::isdigit...) which are locale dependent.
284  * Next functions get parameter as char and don't need double cast ((int)(unsigned char) is required for standard functions). */
285  inline static bool isasciidigit(char chr) // locale independent
286  {
287  return chr >= '0' && chr <= '9';
288  }
289  inline static bool isasciixdigit(char chr) // locale independent
290  {
291  return (chr >= '0' && chr <= '9') || (chr >= 'a' && chr <= 'f') || (chr >= 'A' && chr <= 'F');
292  }
293  static int asciidigitvalue(char chr); // locale independent
294  static int asciixdigitvalue(char chr); // locale independent
295  inline static bool isasciiuppercaseletter(char chr) // locale independent
296  {
297  return (chr >= 'A' && chr <= 'Z');
298  }
299  inline static bool isasciilowercaseletter(char chr) // locale independent
300  {
301  return (chr >= 'a' && chr <= 'z');
302  }
303  inline static bool isasciialphanum(char chr) // locale independent
304  {
305  return isasciiuppercaseletter(chr) || isasciilowercaseletter(chr) || isasciidigit(chr);
306  }
307  static std::string SizeToString(int64_t size);
308  static const std::string Empty;
309  static size_t FindWords(const char *str, const char *wordLowerCase);
310  static int FindEndBracket(const std::string &str, char opener, char closer, int startPos = 0);
311  static int DateStringToYYYYMMDD(const std::string &dateString);
312  static std::string ISODateToLocalizedDate (const std::string& strIsoDate);
313  static void WordToDigits(std::string &word);
314  static std::string CreateUUID();
315  static bool ValidateUUID(const std::string &uuid); // NB only validates syntax
316  static double CompareFuzzy(const std::string &left, const std::string &right);
317  static int FindBestMatch(const std::string &str, const std::vector<std::string> &strings, double &matchscore);
318  static bool ContainsKeyword(const std::string &str, const std::vector<std::string> &keywords);
319 
328  static std::string BinaryStringToString(const std::string& in);
335  static std::string ToHexadecimal(const std::string& in);
344  template<typename T>
345  static std::string FormatNumber(T num)
346  {
347  std::stringstream ss;
348 // ifdef is needed because when you set _ITERATOR_DEBUG_LEVEL=0 and you use custom numpunct you will get runtime error in debug mode
349 // for more info https://connect.microsoft.com/VisualStudio/feedback/details/2655363
350 #if !(defined(_DEBUG) && defined(TARGET_WINDOWS))
351  ss.imbue(GetOriginalLocale());
352 #endif
353  ss.precision(1);
354  ss << std::fixed << num;
355  return ss.str();
356  }
357 
366  static std::string Paramify(const std::string &param);
367 
375  static std::string DeParamify(const std::string& param);
376 
384  static std::vector<std::string> Tokenize(const std::string& input, const std::string& delimiters);
385  static void Tokenize(const std::string& input, std::vector<std::string>& tokens, const std::string& delimiters);
386  static std::vector<std::string> Tokenize(const std::string& input, const char delimiter);
387  static void Tokenize(const std::string& input, std::vector<std::string>& tokens, const char delimiter);
388 
395  static uint32_t ToUint32(std::string_view str, uint32_t fallback = 0) noexcept;
396 
403  static uint64_t ToUint64(std::string_view str, uint64_t fallback = 0) noexcept;
404 
411  static float ToFloat(std::string_view str, float fallback = 0.0f) noexcept;
412 
421  static std::string FormatFileSize(uint64_t bytes);
422 
428  static std::string CreateFromCString(const char* cstr);
429 
436  static bool Contains(std::string_view str,
437  std::string_view keyword,
438  bool isCaseInsensitive = true);
439 
440 private:
445  static const std::locale& GetOriginalLocale() noexcept;
446 };
447 
449 {
450  bool operator()(const std::string& strItem1, const std::string& strItem2) const
451  {
452  return StringUtils::CompareNoCase(strItem1, strItem2) < 0;
453  }
454 };
static bool IsNaturalNumber(const std::string &str)
check whether a string is a natural number. Matches [ ]*[0-9]+[ ]*
Definition: StringUtils.cpp:1513
static std::string BinaryStringToString(const std::string &in)
Convert the string of binary chars to the actual string.
Definition: StringUtils.cpp:1601
static std::string CreateFromCString(const char *cstr)
Converts a cstring pointer (const char*) to a std::string. In case nullptr is passed the result is an...
Definition: StringUtils.cpp:1946
static std::string SecondsToTimeString(long seconds, TIME_FORMAT format=TIME_FORMAT_GUESS)
convert a time in seconds to a string based on the given time format
Definition: StringUtils.cpp:1474
static bool Contains(std::string_view str, std::string_view keyword, bool isCaseInsensitive=true)
Check if a keyword string is contained on another string.
Definition: StringUtils.cpp:1925
Definition: StringUtils.h:448
static bool IsInteger(const std::string &str)
check whether a string is an integer. Matches [ ]*[-]*[0-9]+[ ]*
Definition: StringUtils.cpp:1528
static std::string DeParamify(const std::string &param)
Unescapes the given string.
Definition: StringUtils.cpp:1827
Definition: StringUtils.h:69
static uint32_t ToUint32(std::string_view str, uint32_t fallback=0) noexcept
Converts a string to a unsigned int number.
Definition: StringUtils.cpp:1893
static std::vector< std::string > Split(const std::string &input, const std::string &delimiter, unsigned int iMaxStrings=0)
Splits the given input string using the given delimiter into separate strings.
Definition: StringUtils.cpp:769
static uint64_t ToUint64(std::string_view str, uint64_t fallback=0) noexcept
Converts a string to a unsigned long long number.
Definition: StringUtils.cpp:1898
static std::vector< std::string > Tokenize(const std::string &input, const std::string &delimiters)
Split a string by the specified delimiters. Splits a string using one or more delimiting characters...
Definition: StringUtils.cpp:1847
static std::string FormatNumber(T num)
Format the string with locale separators.
Definition: StringUtils.h:345
static std::string Format(const std::string &fmt, Args &&... args)
Get a formatted string similar to sprintf.
Definition: StringUtils.h:79
static std::string ToHexadecimal(const std::string &in)
Convert each character in the string to its hexadecimal representation and return the concatenated re...
Definition: StringUtils.cpp:1624
static float ToFloat(std::string_view str, float fallback=0.0f) noexcept
Converts a string to a float number.
Definition: StringUtils.cpp:1903
static bool IsSpecialCharacter(char c)
Check if the character is a special character.
Definition: StringUtils.cpp:594
static std::string FormatFileSize(uint64_t bytes)
Definition: StringUtils.cpp:1908
static std::string Paramify(const std::string &param)
Escapes the given string to be able to be used as a parameter.
Definition: StringUtils.cpp:1815
static OutputIt SplitTo(OutputIt d_first, const std::string &input, const std::string &delimiter, unsigned int iMaxStrings=0)
Splits the given input string using the given delimiter into separate strings.
Definition: StringUtils.h:179
static size_t utf8_strlen(const char *s)
utf8 version of strlen - skips any non-starting bytes in the count, thus returning the number of utf8...
Definition: StringUtils.cpp:1804
static std::vector< std::string > SplitMulti(const std::vector< std::string > &input, const std::vector< std::string > &delimiters, size_t iMaxStrings=0)
Splits the given input strings using the given delimiters into further separate strings.
Definition: StringUtils.cpp:790