Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_StringHelper.c
Go to the documentation of this file.
2{
3 static const string LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
4 static const string UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
5 static const string LETTERS = LOWERCASE + UPPERCASE;
6 static const string DIGITS = "0123456789";
7 static const string ALPHANUMERICAL = LETTERS + DIGITS;
8 static const string UNDERSCORE = "_";
9 static const string ALPHANUMERICAL_U = ALPHANUMERICAL + UNDERSCORE;
10 static const string DASH = "-";
11 static const string COLON = ":";
12 static const string SEMICOLON = ";";
13 static const string COMMA = ",";
14 static const string SPACE = " ";
15 static const string STAR = "*";
16 static const string POUND = "#";
17 static const string HASHTAG = POUND;
18 static const string EQUALS = "=";
19 static const string QUESTION_MARK = "?";
20 static const string EXCLAMATION_MARK = "!";
21 static const string ELLIPSIS = "…";
22 static const string DOUBLE_SPACE = SPACE + SPACE;
23 static const string QUADRUPLE_SPACE = DOUBLE_SPACE + DOUBLE_SPACE;
24 static const string SINGLE_QUOTE = "'";
25 static const string DOUBLE_QUOTE = "\"";
26 static const string TAB = "\t";
27 static const string LINE_RETURN = "\n";
28 static const string SLASH = "/";
29 static const string DOUBLE_SLASH = SLASH + SLASH;
30 static const string ANTISLASH = "\\";
31 static const string DOUBLE_ANTISLASH = ANTISLASH + ANTISLASH;
32 static const string LIPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
33 protected static const string TRANSLATION_KEY_CHARS = UNDERSCORE + DASH;
34
35 protected static const int MIN_LC = 97; // a
36 protected static const int MAX_LC = 122; // z
37
38 protected static const int MIN_UC = 65; // A
39 protected static const int MAX_UC = 90; // Z
40
41 protected static const int MIN_DIGIT = 48; // 0
42 protected static const int MAX_DIGIT = 57; // 9
43
44 //------------------------------------------------------------------------------------------------
48 static bool ContainsDigit(string input)
49 {
50 for (int i, len = input.Length(); i < len; i++)
51 {
52 int asciiValue = input[i].ToAscii();
53 if (asciiValue >= MIN_DIGIT && asciiValue <= MAX_DIGIT)
54 return true;
55 }
56
57 return false;
58 }
59
60 //------------------------------------------------------------------------------------------------
64 static bool ContainsUppercase(string input)
65 {
66 for (int i, len = input.Length(); i < len; i++)
67 {
68 int asciiValue = input[i].ToAscii();
69 if (asciiValue >= MIN_UC && asciiValue <= MAX_UC)
70 return true;
71 }
72
73 return false;
74 }
75
76 //------------------------------------------------------------------------------------------------
80 static bool ContainsLowercase(string input)
81 {
82 for (int i, len = input.Length(); i < len; i++)
83 {
84 int asciiValue = input[i].ToAscii();
85 if (asciiValue >= MIN_LC && asciiValue <= MAX_LC)
86 return true;
87 }
88
89 return false;
90 }
91
92 //------------------------------------------------------------------------------------------------
99 static int CountOccurrences(string haystack, string needle, bool caseInsensitive = false)
100 {
101 if (needle.IsEmpty() || haystack.IsEmpty())
102 return 0;
103
104 if (caseInsensitive)
105 {
106 needle.ToLower();
107 haystack.ToLower();
108 }
109
110 int needleLength = needle.Length();
111 int haystackLength = haystack.Length();
112
113 if (needleLength > haystackLength)
114 return 0;
115
116 int result;
117 int searchIndex;
118 while (searchIndex < haystackLength)
119 {
120 int resultIndex = haystack.IndexOfFrom(searchIndex, needle);
121 if (resultIndex < 0)
122 break;
123
124 result++;
125 searchIndex = resultIndex + needleLength;
126 }
127
128 return result;
129 }
130
131 //------------------------------------------------------------------------------------------------
136 static string Filter(string input, string characters, bool useCharactersAsBlacklist = false)
137 {
138 if (input.IsEmpty() || (!useCharactersAsBlacklist && characters.IsEmpty()))
139 return string.Empty;
140
141 string result;
142 for (int i, length = input.Length(); i < length; i++)
143 {
144 string letter = input[i];
145 if (characters.Contains(letter) != useCharactersAsBlacklist) // if it contains but shouldn't, or vice-versa
146 result += letter;
147 }
148
149 return result;
150 }
151
152 //------------------------------------------------------------------------------------------------
155 static bool IsFormat(SCR_EStringFormat format, string input)
156 {
157 switch (format)
158 {
159 case SCR_EStringFormat.ALPHABETICAL_UC: return CheckCharacters(input, false, true, false);
160 case SCR_EStringFormat.ALPHABETICAL_LC: return CheckCharacters(input, true, false, false);
161 case SCR_EStringFormat.ALPHABETICAL_I: return CheckCharacters(input, true, true, false);
162 case SCR_EStringFormat.ALPHANUMERICAL_UC: return CheckCharacters(input, false, true, true);
163 case SCR_EStringFormat.ALPHANUMERICAL_LC: return CheckCharacters(input, true, false, true);
164 case SCR_EStringFormat.ALPHANUMERICAL_I: return CheckCharacters(input, true, true, true);
165 case SCR_EStringFormat.DIGITS_ONLY: return CheckCharacters(input, false, false, true);
166 }
167
168 return false;
169 }
170
171 //------------------------------------------------------------------------------------------------
178 static bool CheckCharacters(string input, bool allowLC, bool allowUC, bool allowDigits, bool allowUnderscore = false)
179 {
180 if (input.IsEmpty())
181 return false;
182
183 for (int i, len = input.Length(); i < len; i++)
184 {
185 int asciiValue = input[i].ToAscii();
186 if (!(
187 (allowLC && asciiValue >= MIN_LC && asciiValue <= MAX_LC) ||
188 (allowUC && asciiValue >= MIN_UC && asciiValue <= MAX_UC) ||
189 (allowDigits && asciiValue >= MIN_DIGIT && asciiValue <= MAX_DIGIT) ||
190 (allowUnderscore && asciiValue == 95)
191 ))
192 return false;
193 }
194
195 return true;
196 }
197
198// //------------------------------------------------------------------------------------------------
199// //! old method, 4-5× slower but allows for non-ASCII values, not useful for now
200// protected static bool CheckCharactersOld(string input, bool allowLC, bool allowUC, bool allowDigits, bool allowUnderscore)
201// {
202// string filter;
203// if (allowLC)
204// filter += LOWERCASE;
205// if (allowUC)
206// filter += UPPERCASE;
207// if (allowDigits)
208// filter += DIGITS;
209// if (allowUnderscore)
210// filter += UNDERSCORE;
211//
212// if (filter.IsEmpty())
213// return false;
214//
215// for (int i, len = input.Length(); i < len; i++)
216// {
217// if (!filter.Contains(input[i]))
218// return false;
219// }
220//
221// return true;
222// }
223
224 //------------------------------------------------------------------------------------------------
229 static string Ellipsis(string input, int maxLength)
230 {
231 if (maxLength < 1)
232 return ELLIPSIS;
233
234 int length = input.Length();
235 if (length <= maxLength)
236 return input;
237
238 return input.Substring(0, maxLength - 1) + ELLIPSIS; // -1 so that adding the ellipsis does not go over the limit
239 }
240
241 //------------------------------------------------------------------------------------------------
246 static string Format(string input, notnull array<string> arguments)
247 {
249 return input;
250
251 if (!input.Contains("%"))
252 return input;
253
254 switch (arguments.Count())
255 {
256 case 0: return string.Format(input);
257 case 1: return string.Format(input, arguments[0]);
258 case 2: return string.Format(input, arguments[0], arguments[1]);
259 case 3: return string.Format(input, arguments[0], arguments[1], arguments[2]);
260 case 4: return string.Format(input, arguments[0], arguments[1], arguments[2], arguments[3]);
261 case 5: return string.Format(input, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
262 case 6: return string.Format(input, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
263 case 7: return string.Format(input, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]);
264 case 8: return string.Format(input, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]);
265 }
266
267 // 9 and more
268 return string.Format(input, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]);
269 }
270
271 //------------------------------------------------------------------------------------------------
275 static string FormatValueNameToUserFriendly(string valueName)
276 {
277 if (IsEmptyOrWhiteSpace(valueName))
278 return string.Empty;
279
280 int asciiValue;
281
282 if (valueName.StartsWith("m_") || valueName.StartsWith("s_"))
283 {
284 int length = valueName.Length();
285 if (length < 3)
286 return string.Empty;
287
288 valueName = valueName.Substring(2, valueName.Length() - 2);
289
290 // is first after prefix letter lowercase
291 asciiValue = valueName[0].ToAscii();
292 if (asciiValue >= MIN_LC && asciiValue <= MAX_LC)
293 {
294 if (length > 3)
295 valueName = valueName.Substring(1, valueName.Length() - 1);
296 }
297
298 if (valueName.IsEmpty())
299 return string.Empty;
300 }
301
302 array<string> pieces = {};
303 string piece;
304 string currChar;
305 int prevCharType; // 0 = LC, 1 = UC, 2 = NUM
306 for (int i, len = valueName.Length(); i < len; i++)
307 {
308 currChar = valueName[i];
309
310 asciiValue = currChar.ToAscii();
311 if (asciiValue >= MIN_LC && asciiValue <= MAX_LC) // lowercase
312 {
313 if (prevCharType < 2) // prev can be lower or upper
314 {
315 piece += currChar;
316 }
317 else
318 {
319 if (!piece.IsEmpty())
320 pieces.Insert(piece);
321
322 piece = currChar;
323 }
324
325 prevCharType = 0;
326 }
327 else if (asciiValue >= MIN_UC && asciiValue <= MAX_UC) // uppercase
328 {
329 bool isNextCharUppercase;
330 if (i < len - 1)
331 {
332 int nextCharAsciiValue = valueName[i + 1].ToAscii();
333 isNextCharUppercase = nextCharAsciiValue >= MIN_UC && nextCharAsciiValue <= MAX_UC;
334 }
335 else // final letter
336 {
337 isNextCharUppercase = true;
338 }
339
340 if (
341 isNextCharUppercase &&
342 prevCharType == 1 &&
343 (asciiValue < MIN_LC || asciiValue > MAX_LC)) // curr char is NOT lowercase
344 {
345 piece += currChar;
346 }
347 else
348 {
349 if (!piece.IsEmpty())
350 pieces.Insert(piece);
351
352 piece = currChar;
353 }
354
355 prevCharType = 1;
356 }
357 else if (asciiValue >= MIN_DIGIT && asciiValue <= MAX_DIGIT) // digits
358 {
359 if (prevCharType == 2)
360 {
361 piece += currChar;
362 }
363 else
364 {
365 if (!piece.IsEmpty())
366 pieces.Insert(piece);
367
368 piece = currChar;
369 }
370
371 prevCharType = 2;
372 }
373 else // anything else
374 {
375 if (!piece.IsEmpty())
376 {
377 pieces.Insert(piece);
378 piece = string.Empty;
379 }
380
381 prevCharType = 0;
382 }
383 }
384
385 if (!piece.IsEmpty())
386 pieces.Insert(piece);
387
388 return Join(SPACE, pieces);
389 }
390
391 //------------------------------------------------------------------------------------------------
396 {
397 array<string> pieces = {};
398 FilePath.StripExtension(FilePath.StripPath(resourceName)).Split(UNDERSCORE, pieces, true);
399 return Join(SPACE, pieces);
400 }
401
402 //------------------------------------------------------------------------------------------------
406 static string FormatSnakeCaseToUserFriendly(string snakeCase)
407 {
408 array<string> pieces = {};
409 snakeCase.Split(UNDERSCORE, pieces, true);
410 foreach (int i, string piece : pieces)
411 {
412 pieces[i] = UCFirst(piece, true);
413 }
414
415 return Join(SPACE, pieces);
416 }
417
418 //------------------------------------------------------------------------------------------------
423 static array<float> GetFloatsFromString(string input, string splitter = SPACE)
424 {
425 array<float> result = {};
426 array<string> splits = {};
427 input.Split(splitter, splits, true);
428
429 foreach (string split : splits)
430 {
431 float value = split.ToFloat();
432 if (value != 0 || split.StartsWith("0"))
433 result.Insert(value);
434 }
435
436 return result;
437 }
438
439 //------------------------------------------------------------------------------------------------
444 static array<int> GetIntsFromString(string input, string splitter = SPACE)
445 {
446 array<int> result = {};
447 array<string> splits = {};
448 input.Split(splitter, splits, true);
449
450 foreach (string split : splits)
451 {
452 int value = split.ToInt();
453 if (value != 0 || split.StartsWith("0"))
454 result.Insert(value);
455 }
456
457 return result;
458 }
459
460 //------------------------------------------------------------------------------------------------
466 static array<string> GetLines(string input, bool removeEmptyLines = false, bool trimLines = false)
467 {
468 if (!input)
469 {
470 if (removeEmptyLines)
471 return {};
472 else
473 return { string.Empty };
474 }
475
476 array<string> result = {};
477 input.Split(LINE_RETURN, result, removeEmptyLines);
478
479 if (trimLines)
480 {
481 for (int i = result.Count() - 1; i >= 0; --i)
482 {
483 string line = result[i];
484 line.TrimInPlace();
485 if (removeEmptyLines && !line)
486 result.RemoveOrdered(i);
487 else
488 result[i] = line;
489 }
490 }
491
492 return result;
493 }
494
495 //------------------------------------------------------------------------------------------------
501 static int IndexOf(string input, notnull array<string> samples)
502 {
503 if (input.IsEmpty() || samples.IsEmpty())
504 return -1;
505
506 int result = int.MAX;
507 foreach (string sample : samples)
508 {
509 int index = input.IndexOf(sample);
510 if (index != -1 && index < result)
511 result = index;
512 }
513
514 if (result == int.MAX)
515 return -1;
516
517 return result;
518 }
519
520 //------------------------------------------------------------------------------------------------
527 static int IndexOfFrom(string input, int start, notnull array<string> samples)
528 {
529 if (start < 0 || start > input.Length() || input.IsEmpty() || samples.IsEmpty())
530 return -1;
531
532 int result = int.MAX;
533 foreach (string sample : samples)
534 {
535 int index = input.IndexOfFrom(start, sample);
536 if (index != -1 && index < result)
537 result = index;
538 }
539
540 if (result == int.MAX)
541 return -1;
542
543 return result;
544 }
545
546 //------------------------------------------------------------------------------------------------
551 array<int> IndicesOf(string input, string search)
552 {
553 if (!input || !search)
554 return {};
555
556 int inputLength = input.Length();
557 int searchLength = search.Length();
558
559 array<int> result = {};
560 for (int i; i < inputLength; ++i)
561 {
562 int index = input.IndexOfFrom(i, search);
563 if (index < 0)
564 break;
565
566 result.Insert(index);
567 if (searchLength > 1)
568 i += searchLength - 1;
569 }
570
571 return result;
572 }
573
574 //------------------------------------------------------------------------------------------------
580 static string InsertAt(string input, string insertion, int insertionIndex = 0)
581 {
582 if (input.IsEmpty() || insertion.IsEmpty() || insertionIndex < 0 || insertionIndex > input.Length())
583 return input;
584
585 if (insertionIndex == 0)
586 return insertion + input;
587
588 return input.Substring(0, insertionIndex) + insertion + input.Substring(insertionIndex, input.Length() - insertionIndex);
589 }
590
591 //------------------------------------------------------------------------------------------------
594 static bool IsEmptyOrWhiteSpace(string input)
595 {
596 return input.Trim().IsEmpty();
597 }
598
599 //------------------------------------------------------------------------------------------------
603 static bool IsTranslationKey(string input)
604 {
605 if (IsEmptyOrWhiteSpace(input))
606 return false;
607
608 if (input != input.Trim())
609 return false;
610
611 if (input.Length() < 2 || !input.StartsWith("#"))
612 return false;
613
614 for (int i, count = TRANSLATION_KEY_CHARS.Length(); i < count; i++)
615 {
616 if (input.EndsWith(TRANSLATION_KEY_CHARS[i]))
617 return false;
618 }
619
620 string filter = LETTERS;
621 if (!filter.Contains(input[1])) // \#[a-zA-Z].*
622 return false;
623
624 filter += DIGITS + TRANSLATION_KEY_CHARS;
625 for (int i, len = input.Length(); i < len; i++)
626 {
627 if (!filter.Contains(input[i]))
628 return false;
629 }
630
631 return true;
632 }
633
634 //------------------------------------------------------------------------------------------------
640 // moved above other methods for autocompletion's sake
641 static string Join(string separator, notnull array<string> pieces, bool joinEmptyEntries = true)
642 {
643 if (pieces.IsEmpty())
644 return string.Empty;
645
646 string result;
647 foreach (int i, string piece : pieces)
648 {
649 if (i == 0)
650 result = piece;
651 else
652 if (joinEmptyEntries || piece) // !piece.IsEmpty()'s fast version
653 result += separator + piece;
654 }
655
656 return result;
657 }
658
659 //------------------------------------------------------------------------------------------------
665 static string Join(string separator, notnull array<bool> pieces, bool numerical = false)
666 {
667 if (pieces.IsEmpty())
668 return string.Empty;
669
670 string result;
671 foreach (int i, bool piece : pieces)
672 {
673 if (i == 0)
674 result = piece.ToString(numerical);
675 else
676 result += separator + piece.ToString(numerical);
677 }
678
679 return result;
680 }
681
682 //------------------------------------------------------------------------------------------------
687 static string Join(string separator, notnull array<int> pieces)
688 {
689 if (pieces.IsEmpty())
690 return string.Empty;
691
692 string result;
693 foreach (int i, int piece : pieces)
694 {
695 if (i == 0)
696 result = piece.ToString();
697 else
698 result += separator + piece;
699 }
700
701 return result;
702 }
703
704 //------------------------------------------------------------------------------------------------
709 static string Join(string separator, notnull array<float> pieces)
710 {
711 if (pieces.IsEmpty())
712 return string.Empty;
713
714 string result;
715 foreach (int i, float piece : pieces)
716 {
717 if (i == 0)
718 result = piece.ToString();
719 else
720 result += separator + piece;
721 }
722
723 return result;
724 }
725
726 //------------------------------------------------------------------------------------------------
733 static int GetLevenshteinDistance(string word1, string word2, bool caseSensitive = true)
734 {
735 if (!word1) // .IsEmpty()
736 return word2.Length();
737
738 if (!word2) // .IsEmpty()
739 return word1.Length();
740
741 if (!caseSensitive)
742 {
743 word1.ToLower();
744 word2.ToLower();
745 }
746
747 if (word1 == word2)
748 return 0;
749
750 int word1Length = word1.Length();
751 int word2Length = word2.Length();
752
753 array<int> v0 = {};
754 array<int> v1 = {};
755 v0.Resize(word1Length + 1);
756 v1.Resize(word1Length + 1);
757
758 for (int i = 1; i <= word1Length; ++i)
759 {
760 v0[i] = i;
761 }
762
763 bool swapped;
764 for (int j = 1; j <= word2Length; ++j)
765 {
766 if (swapped)
767 v0[0] = j;
768 else
769 v1[0] = j;
770
771 for (int i = 1; i <= word1Length; ++i)
772 {
773 int cost = word1[i - 1] != word2[j - 1];
774 if (swapped) // v0[i] = Math.Min(v1[i] + 1, Math.Min(v0[i - 1] + 1, v1[i - 1] + cost));
775 {
776 int min = v1[i] + 1;
777 int tmp = v0[i - 1] + 1;
778 if (tmp < min)
779 min = tmp;
780
781 tmp = v1[i - 1] + cost;
782 if (tmp < min)
783 min = tmp;
784
785 v0[i] = min;
786 }
787 else // v1[i] = Math.Min(v0[i] + 1, Math.Min(v1[i - 1] + 1, v0[i - 1] + cost));
788 {
789 int min = v0[i] + 1;
790 int tmp = v1[i - 1] + 1;
791 if (tmp < min)
792 min = tmp;
793
794 tmp = v0[i - 1] + cost;
795 if (tmp < min)
796 min = tmp;
797
798 v1[i] = min;
799 }
800 }
801
802 swapped = !swapped; // simili vector swap
803 }
804
805 if (swapped)
806 return v1[word1Length];
807 else
808 return v0[word1Length];
809 }
810
811 //------------------------------------------------------------------------------------------------
814 static float GetLevenshteinDistanceScore(string word1, string word2, bool caseSensitive = true)
815 {
816 int distance = GetLevenshteinDistance(word1, word2, caseSensitive);
817 if (distance == 0)
818 return 1.0;
819
820 int word1Length = word1.Length();
821 int word2Length = word2.Length();
822
823 if (word1Length > word2Length)
824 return 1 - distance / word1Length;
825 else
826 return 1 - distance / word2Length;
827 }
828
829 //------------------------------------------------------------------------------------------------
836 static int GetDamerauLevenshteinDistance(string word1, string word2, bool caseSensitive = true)
837 {
838 if (!word1) // .IsEmpty()
839 return word2.Length();
840
841 if (!word2) // .IsEmpty()
842 return word1.Length();
843
844 if (!caseSensitive)
845 {
846 word1.ToLower();
847 word2.ToLower();
848 }
849
850 if (word1 == word2)
851 return 0;
852
853 int word1Length = word1.Length();
854 int word2Length = word2.Length();
855
856 array<int> line;
857 array<ref array<int>> matrix = {};
858 matrix.Reserve(word1Length + 1);
859 for (int i; i <= word1Length; ++i)
860 {
861 line = { i };
862 line.Resize(word2Length + 1);
863 matrix.Insert(line);
864 }
865
866 for (int i = 1; i <= word1Length; ++i)
867 {
868 for (int j = 1; j <= word2Length; ++j)
869 {
870 string word1iMinus1 = word1[i - 1];
871 string word2jMinus1 = word2[j - 1];
872 int cost = word1iMinus1 != word2jMinus1;
873 if (i == 1)
874 matrix[0][j] = j;
875
876 int min = matrix[i - 1][j] + 1;
877 int tmp = matrix[i][j - 1] + 1;
878 if (tmp < min)
879 min = tmp;
880
881 tmp = matrix[i - 1][j - 1] + cost;
882 if (tmp < min)
883 min = tmp;
884
885 if (i > 1 && j > 1)
886 {
887 if (word1iMinus1 == word2[j - 2] && word1[i - 2] == word2jMinus1)
888 {
889 tmp = matrix[i - 2][j - 2] + cost;
890 if (tmp < min)
891 min = tmp;
892 }
893 }
894
895 matrix[i][j] = min;
896 }
897 }
898
899 return matrix[word1Length][word2Length];
900 }
901
902 //------------------------------------------------------------------------------------------------
905 static float GetDamerauLevenshteinDistanceScore(string word1, string word2, bool caseSensitive = true)
906 {
907 int distance = GetDamerauLevenshteinDistance(word1, word2, caseSensitive);
908 if (distance == 0)
909 return 1.0;
910
911 int word1Length = word1.Length();
912 int word2Length = word2.Length();
913
914 if (word1Length > word2Length)
915 return 1 - distance / word1Length;
916 else
917 return 1 - distance / word2Length;
918 }
919
920 //------------------------------------------------------------------------------------------------
928 static string PadLeft(string input, int length, string padding = SPACE)
929 {
930 if (!padding)
931 return input;
932
933 if (input.Length() >= length)
934 return input;
935
936 int padW = padding.Length();
937 for (int i = length - input.Length() - 1; i >= 0; i -= padW)
938 {
939 input = padding + input;
940 }
941
942 if (input.Length() > length)
943 input = input.Substring(input.Length() - length, length);
944
945 return input;
946 }
947
948 //------------------------------------------------------------------------------------------------
956 static string PadRight(string input, int length, string padding = SPACE)
957 {
958 if (!padding)
959 return input;
960
961 if (input.Length() >= length)
962 return input;
963
964 int padW = padding.Length();
965 for (int i = length - input.Length() - 1; i >= 0; i -= padW)
966 {
967 input += padding;
968 }
969
970 if (input.Length() > length)
971 input = input.Substring(0, length);
972
973 return input;
974 }
975
976 //------------------------------------------------------------------------------------------------
988 static string ReplaceRecursive(string input, string sample, string replacement)
989 {
990 if (!input || !sample || sample == replacement || replacement.Contains(sample)) // .IsEmpty() x2
991 return input;
992
993 while (input.IndexOf(sample) > -1)
994 {
995 input.Replace(sample, replacement);
996 }
997
998 return input;
999 }
1000
1001 //------------------------------------------------------------------------------------------------
1007 static string ReplaceMultiple(string input, notnull array<string> samples, string replacement)
1008 {
1009 for (int i = samples.Count() - 1; i >= 0; --i)
1010 {
1011 if (replacement.Contains(samples[i]))
1012 samples.Remove(i);
1013 }
1014
1015 if (samples.IsEmpty())
1016 return input;
1017
1018 foreach (string sample : samples)
1019 {
1020 input.Replace(sample, replacement);
1021 }
1022
1023 return input;
1024 }
1025
1026 //------------------------------------------------------------------------------------------------
1042 static string ReplaceTimes(string input, string sample, string replacement, int howMany = 1, int skip = 0)
1043 {
1044 if (howMany < 1 || input.IsEmpty() || sample.IsEmpty() || sample == replacement)
1045 return input;
1046
1047 int sampleLength = sample.Length();
1048 int replaceLength = replacement.Length();
1049
1050 int index;
1051 while (howMany > 0)
1052 {
1053 index = input.IndexOfFrom(index, sample);
1054 if (index < 0)
1055 break;
1056
1057 if (skip > 0)
1058 {
1059 skip--;
1060 index += sampleLength;
1061 continue;
1062 }
1063
1064 if (index == 0)
1065 input = replacement + input.Substring(sampleLength, input.Length() - sampleLength);
1066 else
1067 input = input.Substring(0, index) + replacement + input.Substring(index + sampleLength, input.Length() - (index + sampleLength));
1068
1069 // no overlap
1070 index += replaceLength;
1071
1072 howMany--;
1073 }
1074
1075 return input;
1076 }
1077
1078 //------------------------------------------------------------------------------------------------
1085 static string Reverse(string input)
1086 {
1087 string result;
1088 for (int i = input.Length() - 1; i >= 0; i--)
1089 {
1090 result += input[i];
1091 }
1092
1093 return result;
1094 }
1095
1096 //------------------------------------------------------------------------------------------------
1109 static bool SimpleStarSearchMatches(string haystack, string needle, bool caseSensitive, bool strictMatch)
1110 {
1111 if (!haystack || !needle) // .IsEmpty()
1112 return false;
1113
1114 if (!caseSensitive)
1115 {
1116 haystack.ToLower();
1117 needle.ToLower();
1118 }
1119
1120 if (!needle.Contains(STAR)) // exact match, boom
1121 return needle == haystack;
1122
1123 bool startsWithStar = needle.StartsWith(STAR);
1124 bool endsWithStar = needle.EndsWith(STAR);
1125
1126 if (startsWithStar)
1127 {
1128 int length = needle.Length();
1129 if (length == 1)
1130 return false;
1131
1132 needle = needle.Substring(1, length - 1);
1133 }
1134
1135 if (endsWithStar)
1136 {
1137 int length = needle.Length();
1138 if (length == 1)
1139 return false;
1140
1141 needle = needle.Substring(0, length - 1);
1142 }
1143
1144 bool isMatch = !strictMatch || needle != haystack;
1145 if (!isMatch)
1146 return false;
1147
1148 if (!startsWithStar && endsWithStar) // starts with needle
1149 return haystack.StartsWith(needle);
1150
1151 if (startsWithStar && endsWithStar) // contains needle
1152 return (!strictMatch || (needle != haystack && !haystack.StartsWith(needle) && !haystack.EndsWith(needle))) && haystack.Contains(needle);
1153
1154 if (startsWithStar && !endsWithStar) // ends with needle
1155 return haystack.EndsWith(needle);
1156
1157 // star in the middle of the word or something
1158 return false;
1159 }
1160
1161 //------------------------------------------------------------------------------------------------
1170 static string UCFirst(string input, bool lcRest = false)
1171 {
1172 if (IsEmptyOrWhiteSpace(input))
1173 return input;
1174
1175 if (lcRest)
1176 input.ToLower();
1177
1178 for (int i, length = input.Length(); i < length; ++i)
1179 {
1180 string c = input[i];
1181 if (!CheckCharacters(c, true, true, true, false))
1182 continue;
1183
1184 if (!CheckCharacters(c, true, false, false, false))
1185 return input;
1186
1187 c.ToUpper();
1188 if (i == 0)
1189 return c + input.Substring(1, length - 1);
1190
1191 if (i == length - 1)
1192 return input.Substring(0, length - 1) + c;
1193
1194 return input.Substring(0, i) + c + input.Substring(i + 1, length - i - 1);
1195 }
1196
1197 return input;
1198 }
1199
1200 //------------------------------------------------------------------------------------------------
1205 static string UCFirstAll(string input, bool lcRest = false)
1206 {
1207 if (IsEmptyOrWhiteSpace(input))
1208 return input;
1209
1210 if (lcRest)
1211 input.ToLower();
1212
1213 const int separatorsCount = 6;
1214 const string separators[separatorsCount] = { " ", "\n", "\t", "-", ":", ";" };
1215
1216 array<string> pieces = {};
1217 for (int i; i < separatorsCount; ++i)
1218 {
1219 string separator = separators[i];
1220 if (!input.Contains(separator))
1221 continue;
1222
1223 input.Split(separator, pieces, false);
1224 foreach (int j, string piece : pieces)
1225 {
1226 pieces[j] = UCFirst(piece, false);
1227 }
1228
1229 input = SCR_StringHelper.Join(separator, pieces, true);
1230 }
1231
1232 return input;
1233 }
1234
1235 //------------------------------------------------------------------------------------------------
1240 static bool ContainsAny(string input, notnull array<string> needles)
1241 {
1242 if (input.IsEmpty())
1243 return false;
1244
1245 foreach (string needle : needles)
1246 {
1247 if (input.Contains(needle))
1248 return true;
1249 }
1250
1251 return false;
1252 }
1253
1254 //------------------------------------------------------------------------------------------------
1259 static bool ContainsEvery(string input, notnull array<string> needles)
1260 {
1261 if (input.IsEmpty())
1262 return false;
1263
1264 foreach (string needle : needles)
1265 {
1266 if (!input.Contains(needle))
1267 return false;
1268 }
1269
1270 return true;
1271 }
1272
1273 //------------------------------------------------------------------------------------------------
1278 static bool ContainsOnly(string input, string characters, bool useCharactersAsBlacklist = false)
1279 {
1280 int inputLength = input.Length();
1281 if (inputLength < 1)
1282 return false;
1283
1284 int charsLength = characters.Length();
1285 if (charsLength < 1)
1286 return true;
1287
1288 if (charsLength == 1) // go the easy way
1289 {
1290 for (int i; i < inputLength; ++i)
1291 {
1292 if ((input[i] == characters) == useCharactersAsBlacklist) // if it contains but shouldn't, or vice-versa
1293 return false;
1294 }
1295
1296 return true;
1297 }
1298
1299 // else // go the hard way
1300
1301 array<int> asciiValues = {};
1302 for (int i; i < charsLength; ++i)
1303 {
1304 asciiValues.Insert(characters[i].ToAscii());
1305 }
1306
1307 for (int i; i < inputLength; i++)
1308 {
1309 if (asciiValues.Contains(input[i].ToAscii()) == useCharactersAsBlacklist)
1310 return false;
1311 }
1312
1313 return true;
1314 }
1315
1316 //------------------------------------------------------------------------------------------------
1321 static bool StartsWithAny(string input, notnull array<string> lineStarts)
1322 {
1323 if (input.IsEmpty())
1324 return false;
1325
1326 foreach (string lineStart : lineStarts)
1327 {
1328 if (input.StartsWith(lineStart))
1329 return true;
1330 }
1331
1332 return false;
1333 }
1334
1335 //------------------------------------------------------------------------------------------------
1340 static bool EndsWithAny(string input, notnull array<string> lineEnds)
1341 {
1342 if (input.IsEmpty())
1343 return false;
1344
1345 foreach (string lineEnd : lineEnds)
1346 {
1347 if (input.EndsWith(lineEnd))
1348 return true;
1349 }
1350
1351 return false;
1352 }
1353
1354
1355 //------------------------------------------------------------------------------------------------
1360 static string TrimLeft(string input)
1361 {
1362 if (input.IsEmpty())
1363 return string.Empty;
1364
1365 for (int i, count = input.Length(); i < count; i++)
1366 {
1367 string character = input[i];
1368 if (character == SPACE || character == TAB || character == LINE_RETURN)
1369 continue;
1370
1371 return input.Substring(i, count - i);
1372 }
1373
1374 return string.Empty;
1375 }
1376
1377 //------------------------------------------------------------------------------------------------
1382 static string TrimRight(string input)
1383 {
1384 if (input.IsEmpty())
1385 return string.Empty;
1386
1387 for (int i = input.Length() - 1; i >= 0; i--)
1388 {
1389 string character = input[i];
1390 if (character == SPACE || character == TAB || character == LINE_RETURN)
1391 continue;
1392
1393 return input.Substring(0, i + 1);
1394 }
1395
1396 return string.Empty;
1397 }
1398}
1399
1400enum SCR_EStringFormat
1401{
1409 // FLOATING_POINT, //!< [0-9][0-9\.]+[0-9]
1410}
ResourceName resourceName
Definition SCR_AIGroup.c:66
float distance
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
class SCR_StringHelper ALPHABETICAL_LC
[a-z]+ (LC = LowerCase)
class SCR_StringHelper ALPHANUMERICAL_LC
[a-z0-9]+ (LC = LowerCase)
class SCR_StringHelper ALPHABETICAL_I
[a-zA-Z]+ (I = Insensitive)
class SCR_StringHelper ALPHANUMERICAL_UC
[A-Z0-9]+ (UC = UpperCase)
class SCR_StringHelper ALPHANUMERICAL_I
[a-zA-Z0-9]+ (I = Insensitive)
class SCR_StringHelper DIGITS_ONLY
[0-9]+
class SCR_StringHelper ALPHABETICAL_UC
[A-Z]+ (UC = UpperCase)
static string FormatSnakeCaseToUserFriendly(string snakeCase)
static string FormatValueNameToUserFriendly(string valueName)
static const int MAX_LC
static int GetLevenshteinDistance(string word1, string word2, bool caseSensitive=true)
static string Filter(string input, string characters, bool useCharactersAsBlacklist=false)
static array< string > GetLines(string input, bool removeEmptyLines=false, bool trimLines=false)
static bool IsTranslationKey(string input)
static const int MIN_LC
static const int MAX_DIGIT
static const int MIN_UC
static string TrimLeft(string input)
static bool ContainsLowercase(string input)
static string PadLeft(string input, int length, string padding=SPACE)
static bool EndsWithAny(string input, notnull array< string > lineEnds)
static string Format(string input, notnull array< string > arguments)
static string UCFirst(string input, bool lcRest=false)
static bool ContainsUppercase(string input)
static bool ContainsOnly(string input, string characters, bool useCharactersAsBlacklist=false)
static string ReplaceRecursive(string input, string sample, string replacement)
static int CountOccurrences(string haystack, string needle, bool caseInsensitive=false)
static string Join(string separator, notnull array< float > pieces)
static bool CheckCharacters(string input, bool allowLC, bool allowUC, bool allowDigits, bool allowUnderscore=false)
static int IndexOfFrom(string input, int start, notnull array< string > samples)
static string UCFirstAll(string input, bool lcRest=false)
static int IndexOf(string input, notnull array< string > samples)
static bool StartsWithAny(string input, notnull array< string > lineStarts)
static bool ContainsAny(string input, notnull array< string > needles)
static array< int > GetIntsFromString(string input, string splitter=SPACE)
static int GetDamerauLevenshteinDistance(string word1, string word2, bool caseSensitive=true)
static string ReplaceTimes(string input, string sample, string replacement, int howMany=1, int skip=0)
static bool ContainsEvery(string input, notnull array< string > needles)
static string Join(string separator, notnull array< bool > pieces, bool numerical=false)
static const int MIN_DIGIT
static const string TRANSLATION_KEY_CHARS
static string PadRight(string input, int length, string padding=SPACE)
static string Join(string separator, notnull array< int > pieces)
static float GetLevenshteinDistanceScore(string word1, string word2, bool caseSensitive=true)
static string Ellipsis(string input, int maxLength)
static string Reverse(string input)
static bool SimpleStarSearchMatches(string haystack, string needle, bool caseSensitive, bool strictMatch)
static bool IsEmptyOrWhiteSpace(string input)
array< int > IndicesOf(string input, string search)
static bool IsFormat(SCR_EStringFormat format, string input)
static array< float > GetFloatsFromString(string input, string splitter=SPACE)
static string TrimRight(string input)
static const int MAX_UC
static bool ContainsDigit(string input)
static string FormatResourceNameToUserFriendly(ResourceName resourceName)
static string Join(string separator, notnull array< string > pieces, bool joinEmptyEntries=true)
static float GetDamerauLevenshteinDistanceScore(string word1, string word2, bool caseSensitive=true)
static string InsertAt(string input, string insertion, int insertionIndex=0)
static string ReplaceMultiple(string input, notnull array< string > samples, string replacement)
@ MAX