HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_StringUtils.h
Go to the documentation of this file.
1 /*
2  * POPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_StringUtils.h
7  *
8  * COMMENTS:
9  *
10  */
11 
12 #ifndef __UT_STRINGUTILS_H__
13 #define __UT_STRINGUTILS_H__
14 
15 #include "UT_API.h"
16 
17 #include "UT_Array.h"
18 #include "UT_StringView.h"
19 
20 #include <SYS/SYS_Compiler.h>
21 #include <SYS/SYS_String.h>
22 #include <SYS/SYS_Inline.h>
23 
24 #include <tuple>
25 #include <type_traits>
26 
27 SYS_FORCE_INLINE bool UTisstring(const char *s) { return s && *s; }
28 
29 template <typename T>
32  const T& str,
33  const char* prefix,
34  bool case_sensitive = true,
35  exint len = -1)
36 {
37  if (!UTisstring(str.data()) || !(prefix && *prefix))
38  return false;
39 
40  if (len < 0)
41  len = strlen(prefix);
42 
43  if (len > str.length())
44  return false;
45 
46  const char* start = str.data();
47  if (case_sensitive)
48  return strncmp(start, prefix, len) == 0;
49  return SYSstrncasecmp(start, prefix, len) == 0;
50 }
51 
52 template <typename T>
55  const T& str,
56  const char* suffix,
57  bool case_sensitive = true,
58  exint len = -1)
59 {
60  if (!UTisstring(str.data()) || !(suffix && *suffix))
61  return false;
62 
63  if (len < 0)
64  len = strlen(suffix);
65 
66  if (len > str.length())
67  return false;
68 
69  const char* start = (str.data() + str.length()) - len;
70  if (case_sensitive)
71  return strncmp(start, suffix, len) == 0;
72  return SYSstrncasecmp(start, suffix, len) == 0;
73 }
74 
75 template <typename T>
76 SYS_NO_DISCARD_RESULT const char *
78  const T& str)
79 {
80  int i = str.length();
81  if (i <= 0)
82  return nullptr;
83 
84  const char* data = str.data();
85  while (i--)
86  {
87  if (!SYSisdigit(data[i]))
88  break;
89  }
90  return &data[i + 1];
91 }
92 
93 template <typename StringT>
95 UTstringFileName(const StringT& str)
96 {
97  // Convert the unknown string type to a string view.
98  UT_StringView view(str.data(), str.length());
99  return UTstringFileName(view);
100 }
101 
102 template <>
105 {
106  if (str.isEmpty())
107  return str;
108 
109  exint pos = str.findLastOf('/');
110  if (pos == UT_StringView::npos)
111  {
112  return str;
113  }
114 
115  // Make sure to move the pos past the '/'
116  return UT_StringView(str.begin() + pos + 1, str.end());
117 }
118 
119 /// Split the given path into the directory, filename, and file extension.
120 template <typename StringT>
121 SYS_NO_DISCARD_RESULT std::tuple<UT_StringView, UT_StringView, UT_StringView>
122 UTstringSplitPath(const StringT& str)
123 {
124  // Convert the unknown string type to a string view.
125  UT_StringView view(str.data(), str.length());
126  return UTstringSplitPath(view);
127 }
128 
129 /// Split the given path into the directory, filename, and file extension.
130 template <>
131 SYS_NO_DISCARD_RESULT inline std::tuple<UT_StringView, UT_StringView, UT_StringView>
133 {
134  if (str.isEmpty())
135  return std::make_tuple(str, str, str);
136 
137  // Parse for the dir
138  UT_StringView dir;
139  exint pos = str.findLastOf('/');
140  if (pos != UT_StringView::npos)
141  dir = UT_StringView(str.begin(), pos + 1);
142 
143  // Parse for the filename and file extension
144  UT_StringView file = UT_StringView(str.begin() + dir.length(), str.end());
145  exint dot = file.findLastOf('.');
146 
147  UT_StringView fname = file;
148  UT_StringView fext;
149  if (dot != UT_StringView::npos)
150  {
151  fname = UT_StringView(file.begin(), dot);
152  fext = UT_StringView(file.begin() + dot, file.end());
153  }
154 
155  return std::make_tuple(dir, fname, fext);
156 }
157 
158 template <typename StringT>
160 UTstringFileExtension(const StringT& str)
161 {
162  // Convert the unknown string type to a string view.
163  UT_StringView view(str.data(), str.length());
164  return UTstringFileExtension(view);
165 }
166 
167 template <>
170 {
171  if (str.isEmpty())
172  return str;
173 
174  exint dot = str.findLastOf('.');
175  if (dot == UT_StringView::npos)
176  {
177  return UT_StringView{};
178  }
179 
180  // Make sure the last dot that is found is after the last '/'.
181  exint slash = str.findLastOf('/');
182  if (slash != UT_StringView::npos && slash > dot)
183  return UT_StringView{};
184 
185  return UT_StringView(str.begin() + dot, str.end());
186 }
187 
188 template <typename StringT>
190 UTstringMatchFileExtension(const StringT& str, const char* extension)
191 {
192  UT_StringView str_extension = UTstringFileExtension(str);
193  return str_extension.equal(extension, false);
194 }
195 
196 template <typename StringT>
198 UTstringCountChar(const StringT& str, int c)
199 {
200  UT_StringView view(str.data(), str.length());
201  return UTstringCountChar(view, c);
202 }
203 
204 template <>
205 SYS_NO_DISCARD_RESULT inline int
207 {
208  if (str.isEmpty())
209  return 0;
210 
211  int count = 0;
212  exint pos = 0;
213  while (pos < str.length())
214  {
215  pos = str.findFirstOf(static_cast<char>(c), pos);
216  if (pos == UT_StringView::npos)
217  break;
218 
219  count++;
220  // Skip past the item that was just found.
221  pos++;
222  }
223 
224  return count;
225 }
226 
227 template <typename StringT>
230  const StringT& str,
231  bool skip_spaces = false,
232  bool loose = false,
233  bool allow_underscore = false)
234 {
235  const char* data = str.data();
236  if (!UTisstring(data))
237  return false;
238 
239  int i = 0;
240  // Skip leading spaces
241  if (skip_spaces)
242  for (; SYSisspace(data[i]); i++)
243  continue;
244 
245  for (; data[i] == '-' || data[i] == '+'; i++)
246  continue;
247 
248  int digit = 0;
249  int ecount = 0;
250  int dotcount = 0;
251  int epos = -10;
252 
253  for (; data[i]; i++)
254  {
255  if (SYSisdigit(data[i]))
256  {
257  digit = 1;
258  continue;
259  }
260  switch (data[i])
261  {
262  case 'e':
263  case 'E':
264  if (ecount)
265  return false;
266  epos = i + 1;
267  ecount = 1;
268  break;
269  case '-':
270  case '+':
271  if (epos != i)
272  return false;
273  epos++;
274  break;
275  case '.':
276  if (ecount || dotcount)
277  return false;
278  dotcount = 1;
279  break;
280  case '_':
281  if (allow_underscore)
282  {
283  // If we have not seen a digit, it is an error.
284  if (!digit)
285  return false;
286  // The actual requirements are tighter than this as
287  // I believe trailing underscores are prohibited.
288  }
289  else
290  {
291  return false;
292  }
293  break;
294  case ' ':
295  case '\t':
296  case '\n':
297  case '\r':
298  case '\f':
299  case '\v':
300  if (!skip_spaces)
301  {
302  return false;
303  }
304  else
305  {
306  // ignore trailing spaces
307  for (; data[i]; i++)
308  if (!SYSisspace(data[i]))
309  return false;
310 
311  if (digit || loose)
312  return true;
313  else
314  return false;
315  }
316 
317  default:
318  return false;
319  }
320  }
321 
322  return (digit || loose);
323 }
324 
325 template <>
326 SYS_NO_DISCARD_RESULT inline bool
328  const UT_StringView& str,
329  bool skip_spaces,
330  bool loose,
331  bool allow_underscore)
332 {
333  // Since UT_StringView may not be null terminated we need to use a
334  // specialized method.
335  return str.isFloat(skip_spaces, loose, allow_underscore);
336 }
337 
338 template <typename StringT>
340 UTstringIsInteger(const StringT& str, bool skip_spaces = false)
341 {
342  const char* cur = str.data();
343 
344  if (!UTisstring(cur))
345  return false;
346 
347  // Skip leading spaces
348  if (skip_spaces)
349  {
350  for (; SYSisspace(*cur); ++cur)
351  ;
352  }
353 
354  // Skip all +'s and -'s
355  for (; *cur == '-' || *cur == '+'; ++cur)
356  ;
357 
358  // Skip all digits
359  for (; SYSisdigit(*cur); ++cur)
360  ;
361 
362  // Skip trailing spaces
363  if (skip_spaces)
364  {
365  for (; SYSisspace(*cur); ++cur)
366  ;
367  }
368 
369  // if we have anything left, this is not an integer
370  if (*cur)
371  return false;
372  return true;
373 }
374 
375 template <>
376 SYS_NO_DISCARD_RESULT inline bool
377 UTstringIsInteger<UT_StringView>(const UT_StringView& str, bool skip_spaces)
378 {
379  // Since UT_StringView may not be null terminated we need to use a
380  // specialized method.
381  return str.isInteger(skip_spaces);
382 }
383 
384 #endif // __UT_STRINGUTILS_H__
385 
SYS_NO_DISCARD_RESULT bool UTstringEndsWith(const T &str, const char *suffix, bool case_sensitive=true, exint len=-1)
GLuint start
Definition: glcorearb.h:475
const GLfloat * c
Definition: glew.h:16631
int64 exint
Definition: SYS_Types.h:125
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const_iterator end() const
Returns a constant iterator pointing to the end of the string.
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:40
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE bool isEmpty() const
Returns true if the string is empty.
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE exint length() const
Returns the length of the string in bytes.
int SYSstrncasecmp(const char *a, const char *b, size_t n)
Definition: SYS_String.h:273
SYS_NO_DISCARD_RESULT UT_StringView UTstringFileName(const StringT &str)
SYS_NO_DISCARD_RESULT bool UTstringIsFloat(const StringT &str, bool skip_spaces=false, bool loose=false, bool allow_underscore=false)
GLenum GLsizei len
Definition: glew.h:7782
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:130
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
SYS_NO_DISCARD_RESULT int UTstringCountChar(const StringT &str, int c)
SYS_NO_DISCARD_RESULT bool UTstringStartsWith(const T &str, const char *prefix, bool case_sensitive=true, exint len=-1)
static constexpr exint npos
Definition: UT_StringView.h:97
#define SYS_NO_DISCARD_RESULT
Definition: SYS_Compiler.h:93
GLint GLsizei count
Definition: glcorearb.h:405
SYS_NO_DISCARD_RESULT std::tuple< UT_StringView, UT_StringView, UT_StringView > UTstringSplitPath(const StringT &str)
Split the given path into the directory, filename, and file extension.
SYS_NO_DISCARD_RESULT bool UTstringIsInteger(const StringT &str, bool skip_spaces=false)
SYS_NO_DISCARD_RESULT bool UTstringIsInteger< UT_StringView >(const UT_StringView &str, bool skip_spaces)
SYS_NO_DISCARD_RESULT UT_StringView UTstringFileExtension(const StringT &str)
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE bool equal(const char *str, bool case_sensitive=true) const
SYS_NO_DISCARD_RESULT bool UTstringMatchFileExtension(const StringT &str, const char *extension)
SYS_NO_DISCARD_RESULT UT_StringView UTstringFileExtension< UT_StringView >(const UT_StringView &str)
SYS_NO_DISCARD_RESULT const char * UTstringNumericSuffix(const T &str)
SYS_FORCE_INLINE bool UTisstring(const char *s)
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const_iterator begin() const
Returns a constant iterator pointing to the beginning of the string.
Definition: core.h:982
SYS_NO_DISCARD_RESULT bool UTstringIsFloat< UT_StringView >(const UT_StringView &str, bool skip_spaces, bool loose, bool allow_underscore)
GLdouble s
Definition: glew.h:1395
SYS_NO_DISCARD_RESULT exint findLastOf(UT_StringView view, exint pos=npos) const noexcept
SYS_NO_DISCARD_RESULT int UTstringCountChar< UT_StringView >(const UT_StringView &str, int c)
OIIO_UTIL_API std::string extension(string_view filepath, bool include_dot=true) noexcept
Definition: format.h:895