Leviathan  0.8.0.0
Leviathan game engine
StringOperations.h
Go to the documentation of this file.
1 // Leviathan Game Engine
2 // Copyright (c) 2012-2018 Henri Hyyryläinen
3 #pragma once
4 // ------------------------------------ //
5 #include "../Utility/Convert.h"
6 
7 #include <memory>
8 #include <string>
9 #include <vector>
10 
11 namespace Leviathan {
12 
13 constexpr int32_t DOT_CHARACTER = '.';
14 constexpr int32_t UNIVERSAL_PATHSEPARATOR = '/';
15 constexpr int32_t WINDOWS_PATHSEPARATOR = '\\';
16 constexpr int32_t SPACE_CHARACTER = ' ';
17 
18 constexpr int32_t FIRST_NUMBER = '0';
19 constexpr int32_t LAST_NUMBER = '9';
20 constexpr int32_t DASH_CHARACTER = '-';
21 constexpr int32_t PLUS_SYMBOL = '+';
22 
23 constexpr char WINDOWS_LINE_SEPARATOR[] = "\r\n";
24 constexpr char UNIVERSAL_LINE_SEPARATOR[] = "\n";
25 
34 public:
35  template<typename CharType>
36  static bool IsCharacterWhitespace(CharType character)
37  {
38  if((int)character <= 32)
39  return true;
40 
41  if(IsLineTerminator(character))
42  return true;
43 
44  return false;
45  }
46 
47  template<typename CharType>
48  static bool IsCharacterQuote(CharType character)
49  {
50  if(character == '"' || character == '\'')
51  return true;
52 
53  return false;
54  }
55 
56  template<typename CharType>
57  static inline bool IsCharacterPathSeparator(CharType character)
58  {
59  if(character == UNIVERSAL_PATHSEPARATOR || character == WINDOWS_PATHSEPARATOR)
60  return true;
61 
62  return false;
63  }
64 
65  // Helper functions //
66 
67  template<class StringTypeN>
68  static void MakeString(StringTypeN& str, const char* characters, size_t count)
69  {
70  // Skip the null terminator //
71  str = StringTypeN(characters, count - 1);
72  }
73 
74  template<class StringTypeN>
75  static StringTypeN RepeatCharacter(int character, size_t count)
76  {
77  StringTypeN result;
78 
79  result.resize(count);
80 
81  for(size_t i = 0; i < count; ++i)
82  result[i] = character;
83 
84  return result;
85  }
86 
87  // ------------------ Path related operations ------------------ //
88  template<class StringTypeN>
89  static const StringTypeN RemoveExtension(const StringTypeN& filepath, bool delpath = true)
90  {
91  size_t startcopy = 0;
92  size_t endcopy;
93 
94  size_t lastdot = filepath.find_last_of(DOT_CHARACTER);
95 
96  if(lastdot == StringTypeN::npos) {
97  // no dot //
98  endcopy = filepath.size() - 1;
99  } else {
100  endcopy = lastdot - 1;
101  }
102 
103  // Potentially erase from beginning //
104  if(delpath) {
105  // Find last path character //
106  size_t lastpath = 0;
107 
108  for(size_t i = 0; i < filepath.size(); i++) {
109  if(filepath[i] == UNIVERSAL_PATHSEPARATOR ||
110  filepath[i] == WINDOWS_PATHSEPARATOR) {
111  // Currently last found path //
112  lastpath = i;
113  }
114  }
115 
116  if(lastpath != 0) {
117  // Set start //
118  startcopy = lastpath + 1;
119  }
120  }
121 
122  // Return empty if no data is valid //
123  if(startcopy > endcopy || startcopy >= filepath.size() || endcopy >= filepath.size())
124  return StringTypeN();
125 
126  // return the wanted part //
127  return filepath.substr(startcopy, endcopy - startcopy + 1);
128  }
129 
130  template<class StringTypeN>
131  static const StringTypeN GetExtension(const StringTypeN& filepath)
132  {
133  size_t startcopy = 0;
134  size_t endcopy = filepath.size() - 1;
135 
136  size_t lastdot = filepath.find_last_of(DOT_CHARACTER);
137 
138  if(lastdot == StringTypeN::npos) {
139  // no dot //
140  return StringTypeN();
141  }
142 
143  startcopy = lastdot + 1;
144 
145  // Return empty if no data is valid //
146  if(startcopy > endcopy || startcopy >= filepath.size() || endcopy >= filepath.size())
147  return StringTypeN();
148 
149  // Return the extension //
150  return filepath.substr(startcopy, endcopy - startcopy + 1);
151  }
152 
153  template<class StringTypeN>
154  static const StringTypeN ChangeExtension(
155  const StringTypeN& filepath, const StringTypeN& newext)
156  {
157  size_t startcopy = 0;
158  size_t endcopy = filepath.size() - 1;
159 
160  size_t lastdot = filepath.find_last_of(DOT_CHARACTER);
161 
162  if(lastdot != StringTypeN::npos) {
163  // dot found //
164  endcopy = lastdot;
165 
166  } else {
167  // No dot, so just append it //
168  return filepath + newext;
169  }
170 
171  // Return empty if no data is valid //
172  if(startcopy > endcopy || startcopy >= filepath.size() || endcopy >= filepath.size())
173  return StringTypeN();
174 
175  // Return the extension //
176  return filepath.substr(startcopy, endcopy - startcopy + 1) + newext;
177  }
178 
179  template<class StringTypeN>
180  static const StringTypeN RemovePath(const StringTypeN& filepath)
181  {
182  size_t startcopy = 0;
183  size_t endcopy = filepath.size() - 1;
184 
185  // Find last path character //
186  size_t lastpath = 0;
187 
188  for(size_t i = 0; i < filepath.size(); i++) {
189  if(filepath[i] == UNIVERSAL_PATHSEPARATOR ||
190  filepath[i] == WINDOWS_PATHSEPARATOR) {
191  // Currently last found path //
192  lastpath = i;
193  }
194  }
195 
196  if(lastpath != 0) {
197  // Set start //
198  startcopy = lastpath + 1;
199  }
200 
201  // Return empty if no data is valid //
202  if(startcopy > endcopy || startcopy >= filepath.size() || endcopy >= filepath.size())
203  return StringTypeN();
204 
205 
206  // return the wanted part //
207  return filepath.substr(startcopy, endcopy - startcopy + 1);
208  }
209 
211  template<class StringTypeN>
212  static const StringTypeN GetPath(const StringTypeN& filepath)
213  {
214  size_t startcopy = 0;
215  size_t endcopy = filepath.size() - 1;
216 
217  // Find last path character //
218  size_t lastpath;
219  bool found = false;
220 
221  for(size_t i = 0; i < filepath.size(); i++) {
222  if(filepath[i] == UNIVERSAL_PATHSEPARATOR ||
223  filepath[i] == WINDOWS_PATHSEPARATOR) {
224  // Currently last found path //
225  lastpath = i;
226  found = true;
227  }
228  }
229 
230  if(!found) {
231  // Set start //
232  return StringTypeN();
233  }
234 
235  // Set up copy //
236  endcopy = lastpath;
237 
238 
239  // Return empty if no data is valid //
240  if(startcopy > endcopy || startcopy >= filepath.size() || endcopy >= filepath.size())
241  return StringTypeN();
242 
243 
244  // return the wanted part //
245  return filepath.substr(startcopy, endcopy - startcopy + 1);
246  }
247 
250  DLLEXPORT static std::string URLProtocol(const std::string& url);
251 
254  DLLEXPORT static std::string BaseHostName(const std::string& url);
255 
262  DLLEXPORT static std::string URLPath(const std::string& url, bool stripoptions = true);
263 
267  DLLEXPORT static std::string CombineURL(
268  const std::string& first, const std::string& second);
269 
274  DLLEXPORT static std::string RemovePartsBeforeAbsoluteURLParts(const std::string& url);
275 
277  DLLEXPORT static bool IsURLDomain(const std::string& str);
278 
279 
281  template<class StringTypeN>
282  static const StringTypeN ChangeLineEndsToWindows(const StringTypeN& input)
283  {
284  StringTypeN results;
285 
286  // This is the line ending sequence //
287  StringTypeN separator;
289 
290  // Try to find path strings and replace them //
291  StartEndIndex copyparts;
292 
293  for(size_t i = 0; i < input.size(); i++) {
294  if(input[i] == UNIVERSAL_LINE_SEPARATOR[0]
295  // Previous character wasn't the first character of a windows line separator.
296  // If it was this is already the correct line separator and should be ignored
297  && (i == 0 || input[i - 1] != WINDOWS_LINE_SEPARATOR[0])) {
298  // Found a line separator //
299  // Copy the current thing //
300  if(copyparts.Start && copyparts.End)
301  results += input.substr(copyparts.Start, copyparts.Length());
302 
303  copyparts.Reset();
304 
305  results += separator;
306 
307  continue;
308  }
309 
310  if(!copyparts.Start)
311  copyparts.Start = i;
312 
313  // Change the end copy //
314  copyparts.End = i;
315  }
316 
317  if(copyparts.End && copyparts.Start)
318  results += input.substr(copyparts.Start, copyparts.Length());
319 
320  return results;
321  }
322 
324  template<class StringTypeN>
325  static const StringTypeN ChangeLineEndsToUniversal(const StringTypeN& input)
326  {
327  StringTypeN results;
328 
329  // This is the line ending sequence //
330  StringTypeN separator;
332 
333  // Try to find path strings and replace them //
334  size_t copystart = 0;
335  size_t copyend = 0;
336 
337  for(size_t i = 0; i < input.size(); i++) {
338  if(input[i] == WINDOWS_LINE_SEPARATOR[0] && i + 1 < input.size() &&
339  input[i + 1] == WINDOWS_LINE_SEPARATOR[1]) {
340  // Found a line separator //
341  // Copy the current thing //
342  if(copyend >= copystart && copystart - copyend > 1)
343  results += input.substr(copystart, copyend - copystart + 1);
344 
345 
346  results += separator;
347 
348  copystart = i + 2 < input.size() ? i + 2 : i;
349  copyend = copystart;
350 
351  i += 2;
352 
353  continue;
354  }
355 
356  // Change the end copy //
357  copyend = i;
358  }
359 
360  if(copyend >= copystart && copystart - copyend > 1)
361  results += input.substr(copystart, copyend - copystart + 1);
362 
363 
364  return results;
365  }
366 
368  template<class StringTypeN>
369  static size_t CutLines(const StringTypeN& input, std::vector<StringTypeN>& output)
370  {
371  if(input.empty())
372  return 0;
373 
374  size_t copystart = 0;
375  size_t copyend = 0;
376 
377  for(size_t i = 0; i < input.size(); i++) {
378  // Check is at a line separator
379  bool windows = input[i] == WINDOWS_LINE_SEPARATOR[0] && i + 1 < input.size() &&
380  input[i + 1] == WINDOWS_LINE_SEPARATOR[1];
381 
382  if(windows || (input[i] == UNIVERSAL_LINE_SEPARATOR[0])) {
383  // Check that previous character wasn't the beginning of
384  // a windows line separator. If it was this is already added
385  // and should be ignored
386  if(i > 0 && input[i - 1] == WINDOWS_LINE_SEPARATOR[0]) {
387 
388  // Skip adding this
389  continue;
390  }
391 
392  // Found a line separator //
393  // Copy the current thing //
394  if(copyend >= copystart && copystart - copyend > 1) {
395 
396  output.push_back(input.substr(copystart, copyend - copystart + 1));
397 
398  } else {
399  // There was an empty line //
400  output.push_back(StringTypeN());
401  }
402 
403  copystart = windows ? i + 2 : i + 1;
404  copyend = 0;
405 
406  continue;
407  }
408 
409  copyend = i;
410  }
411 
412  if(copyend >= copystart)
413  output.push_back(input.substr(copystart, copyend - copystart + 1));
414 
415  return output.size();
416  }
417 
418 
419  // ------------------ General string operations ------------------ //
420  template<class StringTypeN>
421  static bool CutString(const StringTypeN& strtocut, const StringTypeN& separator,
422  std::vector<StringTypeN>& vec)
423  {
424  // scan the input and gather positions for string copying //
425  std::vector<StartEndIndex> CopyOperations;
426  bool PositionStarted = false;
427 
428  for(size_t i = 0; i < strtocut.length(); i++) {
429  if(!PositionStarted) {
430  PositionStarted = true;
431  // add new position index //
432  CopyOperations.push_back(StartEndIndex(i));
433  }
434 
435  if(strtocut[i] == separator[0]) {
436  // Found a possible match //
437  // test further //
438  size_t modifier = 0;
439  bool WasMatch = false;
440  while(strtocut[i + modifier] == separator[modifier]) {
441  // check can it increase without going out of bounds //
442  if((strtocut.length() > i + modifier + 1) &&
443  (separator.length() > modifier + 1)) {
444  // increase modifier to move forward //
445  modifier++;
446  } else {
447  // check is it a match
448  if(modifier + 1 == separator.length()) {
449  // found match! //
450 
451  // end old string to just before this position //
452  CopyOperations.back().End = i; /*-1;
453  not this because we would have to
454  add 1 in the copy phase anyway */
455 
456  PositionStarted = false;
457  // skip separator //
458  WasMatch = true;
459  break;
460  }
461  break;
462  }
463  }
464 
465  // skip the separator amount of characters, if it was found //
466  if(WasMatch)
467  // -1 here so that first character of next string won't be missing,
468  // because of the loop incrementation
469  i += separator.length() - 1;
470  }
471  }
472 
473  // Return empty string if there is nothing here //
474  if(CopyOperations.empty()) {
475 
476  vec.push_back(StringTypeN());
477  return false;
478  }
479 
480  // make sure final position has end //
481  if(!CopyOperations.back().End)
482  CopyOperations.back().End = strtocut.length();
483 
484  if(CopyOperations.size() < 2) {
485 
486  vec.push_back(strtocut.substr(CopyOperations.front().Start,
487  static_cast<size_t>(CopyOperations.front().End) -
488  static_cast<size_t>(CopyOperations.front().Start)));
489 
490  // would be just one string, for legacy
491  // (actually we don't want caller to think it got cut) reasons we return nothing //
492  return false;
493  }
494 
495  // length-1 is not used here, because it would have to be added in copy phase to the
496  // substring length, and we didn't add that earlier...
497 
498  // make space //
499  vec.reserve(CopyOperations.size());
500 
501  // loop through positions and copy substrings to result vector //
502  for(size_t i = 0; i < CopyOperations.size(); i++) {
503  // copy using std::wstring method for speed //
504  vec.push_back(strtocut.substr(
505  CopyOperations[i].Start, static_cast<size_t>(CopyOperations[i].End) -
506  static_cast<size_t>(CopyOperations[i].Start)));
507  }
508 
509  // cutting succeeded //
510  return true;
511  }
512 
513  template<class StringTypeN>
514  static int CountOccuranceInString(const StringTypeN& data, const StringTypeN& lookfor)
515  {
516  int count = 0;
517 
518  for(size_t i = 0; i < data.length(); i++) {
519  if(data[i] == lookfor[0]) {
520  // Found a possible match //
521  // test further //
522  size_t modifier = 0;
523  bool WasMatch = false;
524  while(data[i + modifier] == lookfor[modifier]) {
525  // check can it increase without going out of bounds //
526  if((data.length() > i + modifier + 1) &&
527  (lookfor.length() > modifier + 1)) {
528  // increase modifier to move forward //
529  modifier++;
530  } else {
531  // check is it a match
532  if(modifier + 1 == lookfor.length()) {
533  // found match! //
534  count++;
535  WasMatch = true;
536  break;
537  }
538  break;
539  }
540  }
541  // skip the separator amount of characters, if it was found //
542  if(WasMatch)
543  // -1 here so that first character of next string won't be missing,
544  // because of the loop incrementation
545  i += lookfor.length() - 1;
546  }
547  }
548 
549  return count;
550  }
551 
552  template<class StringTypeN>
553  static StringTypeN Replace(
554  const StringTypeN& data, const StringTypeN& toreplace, const StringTypeN& replacer)
555  {
556  // We construct an output string from the wanted bits //
557  StringTypeN out;
558 
559  if(toreplace.size() < 1) {
560  // Don't replace anything //
561  return data;
562  }
563 
564  PotentiallySetIndex copystart;
565  PotentiallySetIndex copyend;
566 
567  // loop through data and copy final characters to out string //
568  for(size_t i = 0; i < data.size(); i++) {
569  // check for replaced part //
570  if(data[i] == toreplace[0]) {
571  // check for match //
572  bool IsMatch = false;
573  for(size_t checkind = 0;
574  (checkind < toreplace.size()) && (checkind < data.size()); checkind++) {
575  if(data[i + checkind] != toreplace[checkind]) {
576  // didn't match //
577  break;
578  }
579  // check is final iteration //
580  if(!((checkind + 1 < toreplace.size()) && (checkind + 1 < data.size()))) {
581  // is a match //
582  IsMatch = true;
583  break;
584  }
585  }
586 
587  if(IsMatch || toreplace.size() == 1) {
588 
589  if(copystart && !copyend)
590  copyend = copystart;
591 
592  // First add proper characters //
593  if(copystart && copyend)
594  out += data.substr(copystart,
595  static_cast<size_t>(copyend) - static_cast<size_t>(copystart) + 1);
596 
597  copystart.ValueSet = false;
598  copyend.ValueSet = false;
599 
600  // it is a match, copy everything in replacer and
601  // add toreplace length to i
602  out += replacer;
603 
604  i += toreplace.length() - 1;
605  continue;
606  }
607  }
608 
609  // non matching character mark as to copy //
610  if(!copystart) {
611  copystart = i;
612  } else {
613  copyend = i;
614  }
615  }
616 
617  // Copy rest to out //
618  if(copystart && copyend)
619  out += data.substr(
620  copystart, static_cast<size_t>(copyend) - static_cast<size_t>(copystart) + 1);
621 
622  // Return finished string //
623  return out;
624  }
625 
626 
627  template<class StringTypeN>
628  static StringTypeN ReplaceSingleCharacter(
629  const StringTypeN& data, int toreplace, int replacer = ' ')
630  {
631  // Copy the string and then modify it //
632  StringTypeN out(data);
633  ReplaceSingleCharacterInPlace(out, toreplace, replacer);
634 
635  return out;
636  }
637 
638  template<class StringTypeN>
640  StringTypeN& data, int toreplace, int replacer = ' ')
641  {
642  for(auto iter = data.begin(); iter != data.end(); ++iter) {
643  if((*iter) == toreplace)
644  (*iter) = replacer;
645  }
646  }
647 
648  template<class StringTypeN>
649  static StringTypeN RemoveCharacters(const StringTypeN& data, const StringTypeN& toremove)
650  {
651  StringTypeN out;
652  out.reserve(data.size());
653 
654  for(auto iter = data.begin(); iter != data.end(); ++iter) {
655 
656  // Check does it contain //
657  bool ignore = false;
658 
659  for(auto iter2 = toremove.begin(); iter2 != toremove.end(); ++iter2) {
660 
661  if((*iter2) == (*iter)) {
662 
663  ignore = true;
664  break;
665  }
666  }
667 
668  if(ignore)
669  continue;
670 
671  out.push_back(*iter);
672  }
673 
674  return out;
675  }
676 
677  template<class StringTypeN>
678  static StringTypeN RemoveFirstWords(const StringTypeN& data, int amount)
679  {
680  size_t firstpos = 0;
681  // Find the copy start position //
682  int spaces = 0;
683  int words = 0;
684 
685  for(size_t i = 0; i < data.length(); i++) {
686  if(data[i] == SPACE_CHARACTER) {
687  spaces++;
688  continue;
689  }
690  if(spaces > 0) {
691  words++;
692  if(words == amount) {
693  // This is the spot we want to start from //
694  firstpos = i;
695  break;
696  }
697  spaces = 0;
698  }
699  }
700 
701  if(firstpos == 0) {
702  // Didn't remove anything? //
703  return data;
704  }
705 
706  // Generate sub string from start to end //
707  return data.substr(firstpos, data.size() - firstpos);
708  }
709 
710  template<class StringTypeN>
711  static StringTypeN RemovePrefix(const StringTypeN& data, const StringTypeN& prefix)
712  {
713  if(data.find(prefix) == 0) {
714  return data.substr(prefix.size());
715  } else {
716  return data;
717  }
718  }
719 
720  template<class StringTypeN>
721  static StringTypeN StitchTogether(
722  const std::vector<StringTypeN*>& data, const StringTypeN& separator)
723  {
724  StringTypeN ret;
725  bool first = true;
726  // reserve space //
727  int totalcharacters = 0;
728 
729  // This might be faster than not reserving space //
730  for(size_t i = 0; i < data.size(); i++) {
731  totalcharacters += data[i]->length();
732  }
733 
734  totalcharacters += separator.length() * data.size();
735 
736  // By reserving space we don't have to allocate more memory
737  // during copying which might be faster
738  ret.reserve(totalcharacters);
739 
740  for(size_t i = 0; i < data.size(); i++) {
741  if(!first)
742  ret += separator;
743  ret += *data[i];
744  first = false;
745  }
746 
747  return ret;
748  }
749 
750  template<class StringTypeN>
751  static StringTypeN StitchTogether(
752  const std::vector<StringTypeN>& data, const StringTypeN& separator)
753  {
754  StringTypeN ret;
755  bool first = true;
756  // reserve space //
757  int totalcharacters = 0;
758 
759  // This might be faster than not reserving space //
760  for(size_t i = 0; i < data.size(); i++) {
761  totalcharacters += data[i].length();
762  }
763 
764  totalcharacters += separator.length() * data.size();
765 
766  // By reserving space we don't have to allocate more memory
767  // during copying which might be faster
768  ret.reserve(totalcharacters);
769 
770  for(size_t i = 0; i < data.size(); i++) {
771  if(!first)
772  ret += separator;
773  ret += data[i];
774  first = false;
775  }
776 
777  return ret;
778  }
779 
780 
781  template<class StringTypeN>
782  static StringTypeN StitchTogether(
783  const std::vector<std::shared_ptr<StringTypeN>>& data, const StringTypeN& separator)
784  {
785  StringTypeN ret;
786  bool first = true;
787  // reserve space //
788  int totalcharacters = 0;
789 
790  // This might be faster than not reserving space //
791  for(size_t i = 0; i < data.size(); i++) {
792  totalcharacters += data[i]->length();
793  }
794  totalcharacters += separator.length() * data.size();
795 
796  // By reserving space we don't have to allocate more memory during
797  // copying which might be faster
798  ret.reserve(totalcharacters);
799 
800  for(size_t i = 0; i < data.size(); i++) {
801  if(!first)
802  ret += separator;
803  ret += *data[i].get();
804  first = false;
805  }
806 
807  return ret;
808  }
809 
810  template<class StringTypeN>
811  static void RemovePreceedingTrailingSpaces(StringTypeN& str)
812  {
813  StartEndIndex CutPositions;
814 
815  // search the right part of the string //
816  for(size_t i = 0; i < str.size(); i++) {
817  if(!IsCharacterWhitespace(str[i])) {
818  if(!CutPositions.Start) {
819  // beginning ended //
820  CutPositions.Start = i;
821  } else {
822  // set last pos as this //
823  }
824  continue;
825  }
826  if(!CutPositions.Start) {
827  // still haven't found a character //
828  continue;
829  }
830  // check is this last character //
831  size_t a = str.size() - 1;
832  bool found = false;
833  for(; a > i; a--) {
834  if(!IsCharacterWhitespace(str[a])) {
835  // there is still valid characters //
836  found = true;
837  break;
838  }
839  }
840  if(found) {
841  // skip to the found non-space character //
842  i = a - 1;
843  continue;
844  }
845  // end found //
846  CutPositions.End = i - 1;
847  break;
848  }
849 
850  if(!CutPositions.Start) {
851  // nothing in the string //
852  str.clear();
853  return;
854  }
855  if(!CutPositions.End) {
856  if(!CutPositions.Start) {
857  // just the first character required //
858  CutPositions.End = CutPositions.Start;
859  } else {
860  // no need to cut from the end //
861  CutPositions.End = str.length() - 1;
862  }
863  }
864 
865  // set the wstring as it's sub string //
866  str = str.substr(CutPositions.Start, CutPositions.Length());
867  }
868 
869  template<class StringTypeN>
870  static bool CompareInsensitive(const StringTypeN& data, const StringTypeN& second)
871  {
872  if(data.size() != second.size())
873  return false;
874 
875  for(unsigned int i = 0; i < data.size(); i++) {
876  if(data[i] != second[i]) {
877 
878  // Check are they different case //
879  if(97 <= data[i] && data[i] <= 122) {
880 
881  if(data[i] - 32 != second[i]) {
882 
883  return false;
884  }
885  } else if(97 <= second[i] && second[i] <= 122) {
886 
887  if(second[i] - 32 != data[i]) {
888 
889  return false;
890  }
891  } else {
892 
893  return false;
894  }
895  }
896  }
897 
898  return true;
899  }
900 
901  template<class StringTypeN>
902  static bool StringStartsWith(const StringTypeN& data, const StringTypeN& tomatch)
903  {
904  return data.find(tomatch) == 0;
905  }
906 
907  template<class StringTypeN>
908  static bool StringEndsWith(const StringTypeN& data, const StringTypeN& tomatch)
909  {
910  if(data.size() < tomatch.size())
911  return false;
912 
913  if(data.empty())
914  return true;
915 
916  for(size_t i = data.size() - 1, checkIndex = 0; checkIndex < tomatch.size();
917  --i, ++checkIndex) {
918 
919  if(data[i] != tomatch[tomatch.size() - 1 - checkIndex])
920  return false;
921 
922  if(i == 0)
923  return true;
924  }
925 
926  return true;
927  }
928 
929  template<class StringTypeN>
930  static bool IsStringNumeric(const StringTypeN& data)
931  {
932  for(size_t i = 0; i < data.size(); i++) {
933  if((data[i] < FIRST_NUMBER || data[i] > LAST_NUMBER) &&
934  data[i] != DASH_CHARACTER && data[i] != DOT_CHARACTER &&
935  data[i] != PLUS_SYMBOL) {
936  return false;
937  }
938  }
939  return true;
940  }
941 
943  template<class StringTypeN>
944  static StringTypeN ToUpperCase(const StringTypeN& data)
945  {
946  StringTypeN result;
947  result.reserve(data.size());
948 
949  for(size_t i = 0; i < data.size(); i++) {
950 
951  // Not actually unicode decoding...
952  auto const codepoint = data[i];
953 
954  if(97 <= codepoint && codepoint <= 122) {
955 
956  result.push_back(codepoint - 32);
957 
958  } else {
959 
960  result.push_back(codepoint);
961  }
962  }
963 
964  return result;
965  }
966 
967  template<class StringTypeN>
968  static StringTypeN Indent(size_t numspaces)
969  {
970  if(!numspaces)
971  return StringTypeN();
972 
973  return StringTypeN(numspaces, static_cast<int>(' '));
974  }
975 
977  template<class StringTypeN>
978  static StringTypeN IndentLines(const StringTypeN& str, size_t spaces)
979  {
980  const auto indentstr = Indent<StringTypeN>(spaces);
981 
982  StringTypeN result;
983  result.reserve(str.size());
984 
985  StartEndIndex currentcut;
986 
987  for(size_t i = 0; i < str.size(); ++i) {
988 
989  // Check for line change //
990  if(IsLineTerminator(str[i])) {
991 
992  result += indentstr;
993 
994  if(currentcut.Start)
995  result += str.substr(
996  currentcut.Start, i - static_cast<size_t>(currentcut.Start));
997 
998  result += "\n";
999  currentcut = StartEndIndex();
1000 
1001  // Multi character line terminator //
1002  if(i + 1 < str.length() && IsLineTerminator(str[i], str[i + 1]))
1003  ++i;
1004  }
1005 
1006  if(!currentcut.Start && !IsCharacterWhitespace(str[i])) {
1007 
1008  // Started a line //
1009  currentcut.Start = i;
1010  }
1011  }
1012 
1013  if(currentcut.Start) {
1014 
1015  currentcut.End = str.size();
1016 
1017  result += indentstr + str.substr(currentcut.Start, currentcut.Length());
1018  }
1019 
1020  return result;
1021  }
1022 
1023  template<class StringTypeN>
1024  static StringTypeN RemoveEnding(const StringTypeN& str, const StringTypeN& ending)
1025  {
1026  const auto pos = str.rfind(ending);
1027 
1028  if(pos != StringTypeN::npos && str.length() - pos == ending.length())
1029  return str.substr(0, pos);
1030 
1031  return str;
1032  }
1033 
1035  static bool IsLineTerminator(int32_t codepoint)
1036  {
1037  if(codepoint == '\r' || codepoint == '\n' ||
1038  // Unicode newlines //
1039  codepoint == 0x0085 || codepoint == 0x2028 || codepoint == 0x2029 ||
1040  codepoint == 0x000B || codepoint == 0x000C) {
1041  return true;
1042  }
1043 
1044  return false;
1045  }
1046 
1048  static bool IsLineTerminator(int32_t codepoint1, int32_t codepoint2)
1049  {
1050  if(codepoint1 == '\r' && codepoint2 == '\n') {
1051  return true;
1052  }
1053 
1054  return false;
1055  }
1056 
1057 private:
1058  StringOperations() = delete;
1059  ~StringOperations() = delete;
1060 };
1061 
1062 
1063 template<>
1065  std::wstring& str, const char* characters, size_t count);
1066 
1067 } // namespace Leviathan
constexpr int32_t UNIVERSAL_PATHSEPARATOR
static bool IsLineTerminator(int32_t codepoint)
Singleton class that has string processing functions.
static DLLEXPORT std::string CombineURL(const std::string &first, const std::string &second)
static const StringTypeN RemovePath(const StringTypeN &filepath)
static const StringTypeN GetExtension(const StringTypeN &filepath)
static StringTypeN IndentLines(const StringTypeN &str, size_t spaces)
Appends spaces number of spaces to each line in str and returns the result.
static StringTypeN RemoveEnding(const StringTypeN &str, const StringTypeN &ending)
static bool IsStringNumeric(const StringTypeN &data)
static const StringTypeN GetPath(const StringTypeN &filepath)
Returns the path part of a path+filename.
static const StringTypeN RemoveExtension(const StringTypeN &filepath, bool delpath=true)
static void ReplaceSingleCharacterInPlace(StringTypeN &data, int toreplace, int replacer=' ')
static StringTypeN Replace(const StringTypeN &data, const StringTypeN &toreplace, const StringTypeN &replacer)
static StringTypeN StitchTogether(const std::vector< StringTypeN > &data, const StringTypeN &separator)
constexpr char UNIVERSAL_LINE_SEPARATOR[]
static StringTypeN RemoveFirstWords(const StringTypeN &data, int amount)
constexpr int32_t LAST_NUMBER
static size_t CutLines(const StringTypeN &input, std::vector< StringTypeN > &output)
Splits a string on line separators.
static bool IsCharacterPathSeparator(CharType character)
static StringTypeN ToUpperCase(const StringTypeN &data)
static bool IsCharacterQuote(CharType character)
static StringTypeN StitchTogether(const std::vector< StringTypeN * > &data, const StringTypeN &separator)
static DLLEXPORT std::string BaseHostName(const std::string &url)
constexpr int32_t WINDOWS_PATHSEPARATOR
constexpr int32_t DOT_CHARACTER
static StringTypeN Indent(size_t numspaces)
static DLLEXPORT std::string URLProtocol(const std::string &url)
static DLLEXPORT std::string URLPath(const std::string &url, bool stripoptions=true)
static bool IsLineTerminator(int32_t codepoint1, int32_t codepoint2)
static const StringTypeN ChangeExtension(const StringTypeN &filepath, const StringTypeN &newext)
static DLLEXPORT std::string RemovePartsBeforeAbsoluteURLParts(const std::string &url)
static StringTypeN RepeatCharacter(int character, size_t count)
size_t Length() const
Definition: Types.h:113
constexpr int32_t SPACE_CHARACTER
static StringTypeN RemoveCharacters(const StringTypeN &data, const StringTypeN &toremove)
constexpr int32_t DASH_CHARACTER
static bool StringStartsWith(const StringTypeN &data, const StringTypeN &tomatch)
static bool IsCharacterWhitespace(CharType character)
constexpr int32_t PLUS_SYMBOL
static const StringTypeN ChangeLineEndsToUniversal(const StringTypeN &input)
Changes all line separators to universal line separators.
static StringTypeN StitchTogether(const std::vector< std::shared_ptr< StringTypeN >> &data, const StringTypeN &separator)
static bool CompareInsensitive(const StringTypeN &data, const StringTypeN &second)
static void RemovePreceedingTrailingSpaces(StringTypeN &str)
#define DLLEXPORT
Definition: Include.h:84
static bool StringEndsWith(const StringTypeN &data, const StringTypeN &tomatch)
constexpr char WINDOWS_LINE_SEPARATOR[]
static StringTypeN RemovePrefix(const StringTypeN &data, const StringTypeN &prefix)
static void MakeString(StringTypeN &str, const char *characters, size_t count)
constexpr int32_t FIRST_NUMBER
static bool CutString(const StringTypeN &strtocut, const StringTypeN &separator, std::vector< StringTypeN > &vec)
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
static const StringTypeN ChangeLineEndsToWindows(const StringTypeN &input)
Changes all line separators to Windows line separators.
static StringTypeN ReplaceSingleCharacter(const StringTypeN &data, int toreplace, int replacer=' ')
static int CountOccuranceInString(const StringTypeN &data, const StringTypeN &lookfor)
void Reset()
Reset the Start and End to unset.
Definition: Types.h:105
static DLLEXPORT bool IsURLDomain(const std::string &str)
Returns true if string looks like a top level domain.