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