TrueReality  v0.1.1912
StringUtils.cpp
Go to the documentation of this file.
1 /*
2 * True Reality Open Source Game and Simulation Engine
3 * Copyright © 2021 Acid Rain Studios LLC
4 *
5 * The Base of this class has been adopted from the Delta3D engine
6 *
7 * This library is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the Free
9 * Software Foundation; either version 3.0 of the License, or (at your option)
10 * any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 * details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * @author David Guthrie
22 * @author John K. Grant
23 * @author William E. Johnson II
24 * @author Chris Osborn
25 * @author Maxim Serebrennik
26 */
27 #include <trUtil/StringUtils.h>
28 
29 #include <trUtil/Logging/Log.h>
30 #include <trUtil/PlatformMacros.h>
31 
32 #include <iomanip>
33 
34 namespace trUtil::StringUtils
35 {
36 
37 #ifdef TR_WIN
38  const std::string IsSpace::DEFAULT_LOCALE_NAME("english");
39 #elif defined (TR_APPLE)
40  const std::string IsSpace::DEFAULT_LOCALE_NAME("C");
41 #else
42  const std::string IsSpace::DEFAULT_LOCALE_NAME("en_US.UTF-8");
43 #endif
44 
45 #ifdef TR_WIN
46 #ifndef strCmp
47 #define strCmp _stricmp
48 #include <string.h>
49 #endif
50 #else
51 #ifndef strCmp
52 #define strCmp strcasecmp
53 #include <strings.h>
54 #endif
55 #endif
56 
58  const std::string& Trim(std::string& toTrim)
59  {
60  while (!toTrim.empty() && isspace(static_cast<unsigned char>(toTrim[toTrim.length() - 1])))
61  {
62  toTrim.erase(toTrim.length() - 1);
63  }
64 
65  while (!toTrim.empty() && isspace(static_cast<unsigned char>(toTrim[0])))
66  {
67  toTrim.erase(0, 1);
68  }
69 
70  return toTrim;
71  }
72 
74  int StrCompare(const std::string& one, const std::string& two, bool caseSensitive)
75  {
76  int result = 0;
77  if (caseSensitive)
78  {
79  result = one.compare(two);
80  }
81  else
82  {
83  result = strCmp(one.c_str(), two.c_str());
84  }
85  return result;
86  }
87 
89  void ToLowerCase(std::string& str)
90  {
91  for (unsigned i = 0; i < str.size(); ++i)
92  {
93  str[i] = tolower(str[i]);
94  }
95  }
96 
98  std::string ToLowerCase(const std::string& str)
99  {
100  std::string newStr = str;
101 
102  ToLowerCase(newStr);
103  return newStr;
104  }
105 
107  void ToUpperCase(std::string& str)
108  {
109  for (unsigned i = 0; i < str.size(); ++i)
110  {
111  str[i] = toupper(str[i]);
112  }
113  }
114 
116  std::string ToUpperCase(const std::string& str)
117  {
118  std::string newStr = str;
119 
120  ToUpperCase(newStr);
121  return newStr;
122  }
123 
125  template<>
126  bool FromString<bool>(const std::string& u)
127  {
128  return u == "1" || u == "true" || u == "True" || u == "TRUE";
129  }
130 
131 
133  static bool Scan(const char*& wildCards, const char*& str)
134  {
135  // scan '?' and '*'
136 
137  // remove the '?' and '*'
138  for (wildCards++; *str != '\0' && (*wildCards == '?' || *wildCards == '*'); ++wildCards)
139  {
140  if (*wildCards == '?')
141  {
142  ++str;
143  }
144  }
145 
146  while (*wildCards == '*')
147  {
148  wildCards++;
149  }
150 
151  // if str is empty and Wildcards has more characters or,
152  // Wildcards is empty, return
153  if (*str == '\0' && *wildCards != '\0')
154  {
155  return false;
156  }
157  else if (*str == '\0' && *wildCards == '\0')
158  {
159  return true;
160  // else search substring
161  }
162  else
163  {
164  const char* wdsCopy = wildCards;
165  const char* strCopy = str;
166  bool Yes = true;
167  do
168  {
169  if (!Match(wildCards, str)) { ++strCopy; }
170  wildCards = wdsCopy;
171  str = strCopy;
172  while ((*wildCards != *str) && (*str != '\0')) { ++str; }
173  wdsCopy = wildCards;
174  strCopy = str;
175  } while ((*str != '\0') ? !Match(wildCards, str) : (Yes = false) != false);
176 
177  if (*str == '\0' && *wildCards == '\0')
178  {
179  return true;
180  }
181 
182  return Yes;
183  }
184  }
185 
187  static bool WildMatch(const char* wildCards, const char* str)
188  {
189  bool Yes = true;
190 
191  // iterate and delete '?' and '*' one by one
192  while (*wildCards != '\0' && Yes && *str != '\0')
193  {
194  if (*wildCards == '?')
195  {
196  ++str;
197  }
198  else if (*wildCards == '*')
199  {
200  Yes = Scan(wildCards, str);
201  --wildCards;
202  }
203  else
204  {
205  Yes = (*wildCards == *str);
206  ++str;
207  }
208  ++wildCards;
209  }
210  while (*wildCards == '*' && Yes) { ++wildCards; }
211 
212  return Yes && *str == '\0' && *wildCards == '\0';
213  }
214 
216  bool Match(const char* Wildcards, const char* str)
217  {
218  return WildMatch(Wildcards, str);
219  }
220 
222  void MakeIndexString(unsigned index, std::string& toFill, unsigned paddedLength)
223  {
224  std::ostringstream ss;
225  ss << std::setfill('0') << std::setw(paddedLength);
226  ss << index;
227  ss.str().swap(toFill);
228  }
229 
231  bool TakeToken(std::string& data, std::string& outToken, char openChar, char closeChar)
232  {
233  bool result = true;
234  outToken.clear();
235 
236  if (data.empty())
237  {
238  result = false;
239  }
240  // If the first character in the data string is not the opening character,
241  // we will just assume the entire data string is the token.
242  else if (data.c_str()[0] != openChar)
243  {
244  outToken = data;
245  data.clear();
246  }
247  else
248  {
249  int depth = 0;
250  int dataIndex = 0;
251  while (!data.empty())
252  {
253  bool appendChar = true;
254 
255  // Opening characters increase the depth counter.
256  if (data[dataIndex] == openChar)
257  {
258  depth++;
259 
260  if (depth == 1)
261  {
262  appendChar = false;
263  }
264  }
265  // Closing characters decrease the depth counter.
266  else if (data[dataIndex] == closeChar)
267  {
268  depth--;
269 
270  if (depth == 0)
271  {
272  appendChar = false;
273  }
274  }
275 
276  // All other characters are added to the return buffer.
277  if (appendChar)
278  {
279  outToken.append(data.c_str(), 1);
280  }
281 
282  // Remove the left most character from the data string.
283  // Some versions of the stl can be picky so don't allow the subscript to go out of range.
284  if (data.length() > 1)
285  {
286  data = &data[1];
287  }
288  else
289  {
290  // Don't leave leftovers like brackets
291  data.clear();
292  }
293 
294  // We are done once our depth returns to 0.
295  if (depth <= 0)
296  {
297  break;
298  }
299  }
300  // we ran out of string, so we stopped reading, which means the data is invalid.
301  if (depth > 0)
302  {
303  result = false;
304  }
305  }
306  return result;
307  }
308 
310  void FindAndReplace(std::string& modifiedString, const std::string& findWhat, const std::string& replaceWith)
311  {
312  if (!findWhat.empty())
313  {
314  size_t pos = 0;
315  while ((pos = modifiedString.find(findWhat, pos)) != std::string::npos)
316  {
317  modifiedString.replace(pos, findWhat.length(), replaceWith);
318  pos += replaceWith.length();
319  }
320  }
321  else
322  {
323  LOG_E("Trying to find an empty string within a string.");
324  }
325  }
326 }
#define strCmp
Definition: StringUtils.cpp:52
static bool WildMatch(const char *wildCards, const char *str)
static const std::string DEFAULT_LOCALE_NAME
Definition: StringUtils.h:136
static bool Scan(const char *&wildCards, const char *&str)
bool TR_UTIL_EXPORT Match(const char *wildCards, const char *str)
Matches.
bool TR_UTIL_EXPORT TakeToken(std::string &data, std::string &outToken, char openChar, char closeChar)
Reads the next token fromm the given string data.
void TR_UTIL_EXPORT FindAndReplace(std::string &modifiedString, const std::string &findWhat, const std::string &replaceWith)
Finds all instances of the findWhat string in the string modifiedString and replaces them with the re...
bool TR_UTIL_EXPORT FromString< bool >(const std::string &u)
Special exception for bool where things like "True", "TRUE", and "true" should be accepted...
#define LOG_E(msg)
Log an ERROR message.
Definition: Log.h:165
TR_UTIL_EXPORT const std::string & Trim(std::string &toTrim)
Trims whitespace off the front and end of a string.
Definition: StringUtils.cpp:58
TR_UTIL_EXPORT void ToUpperCase(std::string &str)
Converts the whole string to upper case.
TR_UTIL_EXPORT int StrCompare(const std::string &one, const std::string &two, bool caseSensitive=true)
Compares strings like strcmp or stricmp or strcasecmp.
Definition: StringUtils.cpp:74
void TR_UTIL_EXPORT MakeIndexString(unsigned index, std::string &toFill, unsigned paddedLength=4)
Makes index string.
TR_UTIL_EXPORT void ToLowerCase(std::string &str)
Converts the whole string to lower case.
Definition: StringUtils.cpp:89