xbmc
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  static int Replace(std::string &str, char oldChar, char newChar);
120  static int Replace(std::string &str, const std::string &oldStr, const std::string &newStr);
121  static int Replace(std::wstring &str, const std::wstring &oldStr, const std::wstring &newStr);
122  static bool StartsWith(const std::string &str1, const std::string &str2);
123  static bool StartsWith(const std::string &str1, const char *s2);
124  static bool StartsWith(const char *s1, const char *s2);
125  static bool StartsWithNoCase(const std::string &str1, const std::string &str2);
126  static bool StartsWithNoCase(const std::string &str1, const char *s2);
127  static bool StartsWithNoCase(const char *s1, const char *s2);
128  static bool EndsWith(const std::string &str1, const std::string &str2);
129  static bool EndsWith(const std::string &str1, const char *s2);
130  static bool EndsWithNoCase(const std::string &str1, const std::string &str2);
131  static bool EndsWithNoCase(const std::string &str1, const char *s2);
132 
133  template<typename CONTAINER>
134  static std::string Join(const CONTAINER &strings, const std::string& delimiter)
135  {
136  std::string result;
137  for (const auto& str : strings)
138  result += str + delimiter;
139 
140  if (!result.empty())
141  result.erase(result.size() - delimiter.size());
142  return result;
143  }
144 
154  static std::vector<std::string> Split(const std::string& input, const std::string& delimiter, unsigned int iMaxStrings = 0);
155  static std::vector<std::string> Split(const std::string& input, const char delimiter, size_t iMaxStrings = 0);
156  static std::vector<std::string> Split(const std::string& input, const std::vector<std::string> &delimiters);
168  template<typename OutputIt>
169  static OutputIt SplitTo(OutputIt d_first, const std::string& input, const std::string& delimiter, unsigned int iMaxStrings = 0)
170  {
171  OutputIt dest = d_first;
172 
173  if (input.empty())
174  return dest;
175  if (delimiter.empty())
176  {
177  *d_first++ = input;
178  return dest;
179  }
180 
181  const size_t delimLen = delimiter.length();
182  size_t nextDelim;
183  size_t textPos = 0;
184  do
185  {
186  if (--iMaxStrings == 0)
187  {
188  *dest++ = input.substr(textPos);
189  break;
190  }
191  nextDelim = input.find(delimiter, textPos);
192  *dest++ = input.substr(textPos, nextDelim - textPos);
193  textPos = nextDelim + delimLen;
194  } while (nextDelim != std::string::npos);
195 
196  return dest;
197  }
198  template<typename OutputIt>
199  static OutputIt SplitTo(OutputIt d_first, const std::string& input, const char delimiter, size_t iMaxStrings = 0)
200  {
201  return SplitTo(d_first, input, std::string(1, delimiter), iMaxStrings);
202  }
203  template<typename OutputIt>
204  static OutputIt SplitTo(OutputIt d_first, const std::string& input, const std::vector<std::string> &delimiters)
205  {
206  OutputIt dest = d_first;
207  if (input.empty())
208  return dest;
209 
210  if (delimiters.empty())
211  {
212  *dest++ = input;
213  return dest;
214  }
215  std::string str = input;
216  for (size_t di = 1; di < delimiters.size(); di++)
217  StringUtils::Replace(str, delimiters[di], delimiters[0]);
218  return SplitTo(dest, str, delimiters[0]);
219  }
220 
235  static std::vector<std::string> SplitMulti(const std::vector<std::string>& input,
236  const std::vector<std::string>& delimiters,
237  size_t iMaxStrings = 0);
238  static int FindNumber(const std::string& strInput, const std::string &strFind);
239  static int64_t AlphaNumericCompare(const wchar_t *left, const wchar_t *right);
240  static int AlphaNumericCollation(int nKey1, const void* pKey1, int nKey2, const void* pKey2);
241  static long TimeStringToSeconds(const std::string &timeString);
242  static void RemoveCRLF(std::string& strLine);
243 
248  static size_t utf8_strlen(const char *s);
249 
256  static std::string SecondsToTimeString(long seconds, TIME_FORMAT format = TIME_FORMAT_GUESS);
257 
263  static bool IsNaturalNumber(const std::string& str);
264 
270  static bool IsInteger(const std::string& str);
271 
272  /* The next several isasciiXX and asciiXXvalue functions are locale independent (US-ASCII only),
273  * as opposed to standard ::isXX (::isalpha, ::isdigit...) which are locale dependent.
274  * Next functions get parameter as char and don't need double cast ((int)(unsigned char) is required for standard functions). */
275  inline static bool isasciidigit(char chr) // locale independent
276  {
277  return chr >= '0' && chr <= '9';
278  }
279  inline static bool isasciixdigit(char chr) // locale independent
280  {
281  return (chr >= '0' && chr <= '9') || (chr >= 'a' && chr <= 'f') || (chr >= 'A' && chr <= 'F');
282  }
283  static int asciidigitvalue(char chr); // locale independent
284  static int asciixdigitvalue(char chr); // locale independent
285  inline static bool isasciiuppercaseletter(char chr) // locale independent
286  {
287  return (chr >= 'A' && chr <= 'Z');
288  }
289  inline static bool isasciilowercaseletter(char chr) // locale independent
290  {
291  return (chr >= 'a' && chr <= 'z');
292  }
293  inline static bool isasciialphanum(char chr) // locale independent
294  {
295  return isasciiuppercaseletter(chr) || isasciilowercaseletter(chr) || isasciidigit(chr);
296  }
297  static std::string SizeToString(int64_t size);
298  static const std::string Empty;
299  static size_t FindWords(const char *str, const char *wordLowerCase);
300  static int FindEndBracket(const std::string &str, char opener, char closer, int startPos = 0);
301  static int DateStringToYYYYMMDD(const std::string &dateString);
302  static std::string ISODateToLocalizedDate (const std::string& strIsoDate);
303  static void WordToDigits(std::string &word);
304  static std::string CreateUUID();
305  static bool ValidateUUID(const std::string &uuid); // NB only validates syntax
306  static double CompareFuzzy(const std::string &left, const std::string &right);
307  static int FindBestMatch(const std::string &str, const std::vector<std::string> &strings, double &matchscore);
308  static bool ContainsKeyword(const std::string &str, const std::vector<std::string> &keywords);
309 
318  static std::string BinaryStringToString(const std::string& in);
325  static std::string ToHexadecimal(const std::string& in);
334  template<typename T>
335  static std::string FormatNumber(T num)
336  {
337  std::stringstream ss;
338 // ifdef is needed because when you set _ITERATOR_DEBUG_LEVEL=0 and you use custom numpunct you will get runtime error in debug mode
339 // for more info https://connect.microsoft.com/VisualStudio/feedback/details/2655363
340 #if !(defined(_DEBUG) && defined(TARGET_WINDOWS))
341  ss.imbue(GetOriginalLocale());
342 #endif
343  ss.precision(1);
344  ss << std::fixed << num;
345  return ss.str();
346  }
347 
356  static std::string Paramify(const std::string &param);
357 
365  static std::string DeParamify(const std::string& param);
366 
374  static std::vector<std::string> Tokenize(const std::string& input, const std::string& delimiters);
375  static void Tokenize(const std::string& input, std::vector<std::string>& tokens, const std::string& delimiters);
376  static std::vector<std::string> Tokenize(const std::string& input, const char delimiter);
377  static void Tokenize(const std::string& input, std::vector<std::string>& tokens, const char delimiter);
378 
385  static uint32_t ToUint32(std::string_view str, uint32_t fallback = 0) noexcept;
386 
393  static uint64_t ToUint64(std::string_view str, uint64_t fallback = 0) noexcept;
394 
401  static float ToFloat(std::string_view str, float fallback = 0.0f) noexcept;
402 
411  static std::string FormatFileSize(uint64_t bytes);
412 
418  static std::string CreateFromCString(const char* cstr);
419 
426  static bool Contains(std::string_view str,
427  std::string_view keyword,
428  bool isCaseInsensitive = true);
429 
430 private:
435  static const std::locale& GetOriginalLocale() noexcept;
436 };
437 
439 {
440  bool operator()(const std::string& strItem1, const std::string& strItem2) const
441  {
442  return StringUtils::CompareNoCase(strItem1, strItem2) < 0;
443  }
444 };
static bool IsNaturalNumber(const std::string &str)
check whether a string is a natural number. Matches [ ]*[0-9]+[ ]*
Definition: StringUtils.cpp:1480
static std::string BinaryStringToString(const std::string &in)
Convert the string of binary chars to the actual string.
Definition: StringUtils.cpp:1568
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:1913
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:1441
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:1892
Definition: StringUtils.h:438
static bool IsInteger(const std::string &str)
check whether a string is an integer. Matches [ ]*[-]*[0-9]+[ ]*
Definition: StringUtils.cpp:1495
static std::string DeParamify(const std::string &param)
Unescapes the given string.
Definition: StringUtils.cpp:1794
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:1860
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:736
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:1865
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:1814
static std::string FormatNumber(T num)
Format the string with locale separators.
Definition: StringUtils.h:335
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:1591
static float ToFloat(std::string_view str, float fallback=0.0f) noexcept
Converts a string to a float number.
Definition: StringUtils.cpp:1870
static std::string FormatFileSize(uint64_t bytes)
Definition: StringUtils.cpp:1875
static std::string Paramify(const std::string &param)
Escapes the given string to be able to be used as a parameter.
Definition: StringUtils.cpp:1782
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:169
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:1771
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:757