diff --git a/sources/Text/BaseText.uc b/sources/Text/BaseText.uc index 90e7b48..1c62fde 100644 --- a/sources/Text/BaseText.uc +++ b/sources/Text/BaseText.uc @@ -1332,19 +1332,29 @@ public final function string ToFormattedString( * If `separator` does not match anywhere in the string, method returns a * single-element array containing copy of this `Text`. * - * @param separator Character that separates different parts of this `Text`. - * @param skipEmpty Set this to `true` to filter out empty `MutableText`s - * from the output. - * @return Array of `MutableText`s that contain separated substrings. + * @param separator Character that separates different parts of + * this `Text`. If `separator` is an invalid character, method will do + * nothing and return empty result. + * @param skipEmpty Set this to `true` to filter out empty + * `MutableText`s from the output. + * @param returnMutable Decides whether this method will return + * `Text` (`false`, by default) or `MutableText` (`true`) instances. + * @return Array of `BaseText`s (whether it's `Text` or `MutableText` depends + * on `returnMutable` parameter) that contain separated substrings. + * Always empty if `separator` is an invalid character. */ -public final function array SplitByCharacter( +public final function array SplitByCharacter( Character separator, - optional bool skipEmpty) + optional bool skipEmpty, + optional bool returnMutable) { - local int i, length; - local Character nextCharacter; - local MutableText nextText; - local array result; + local int i, length; + local Character nextCharacter; + local MutableText nextText; + local array result; + if (!_.text.IsValidCharacter(separator)) { + return result; + } length = GetLength(); nextText = _.text.Empty(); i = 0; @@ -1353,8 +1363,14 @@ public final function array SplitByCharacter( nextCharacter = GetCharacter(i); if (_.text.AreEqual(separator, nextCharacter)) { - if (!skipEmpty || !nextText.IsEmpty()) { - result[result.length] = nextText; + if (!skipEmpty || !nextText.IsEmpty()) + { + if (returnMutable) { + result[result.length] = nextText; + } + else { + result[result.length] = nextText.IntoText(); + } } else { _.memory.Free(nextText); @@ -1366,12 +1382,46 @@ public final function array SplitByCharacter( } i += 1; } - if (!skipEmpty || !nextText.IsEmpty()) { - result[result.length] = nextText; + if (!skipEmpty || !nextText.IsEmpty()) + { + if (returnMutable) { + result[result.length] = nextText; + } + else { + result[result.length] = nextText.IntoText(); + } } return result; } +/** + * Splits the string into substrings wherever `separator` occurs, and returns + * array of those strings. + * + * If `separator` does not match anywhere in the string, method returns a + * single-element array containing copy of this `Text`. + * + * @param separatorSource `string`, first character of which will be used as + * a separator. If `separatorSource` is empty, method will do nothing and + * return empty result. + * @param skipEmpty Set this to `true` to filter out empty + * `MutableText`s from the output. + * @param returnMutable Decides whether this method will return + * `Text` (`false`, by default) or `MutableText` (`true`) instances. + * @return Array of `BaseText`s (whether it's `Text` or `MutableText` depends + * on `returnMutable` parameter) that contain separated substrings. + * Always empty if `separatorSource` is empty. + */ +public final function array SplitByCharacterS( + string separatorSource, + optional bool skipEmpty, + optional bool returnMutable) +{ + local Character separator; + separator = _.text.GetCharacter(separatorSource, 0); + return SplitByCharacter(separator, skipEmpty, returnMutable); +} + /** * Returns the index position of the first occurrence of the `otherText` in * the caller `BaseText`, searching forward from index position `fromIndex`. diff --git a/sources/Text/FormattedStrings/FormattingStringParser.uc b/sources/Text/FormattedStrings/FormattingStringParser.uc index 44858b1..791f2df 100644 --- a/sources/Text/FormattedStrings/FormattingStringParser.uc +++ b/sources/Text/FormattedStrings/FormattingStringParser.uc @@ -321,19 +321,19 @@ private final function Color GetColorFor(int index) private final function FormattingInfo ParseFormattingInfo(BaseText colorTag) { - local int i; - local Parser colorParser; - local Color nextColor; - local array specifiedColors; - local array gradientColors; - local array gradientPoints; - local FormattingInfo targetInfo; + local int i; + local Parser colorParser; + local Color nextColor; + local array specifiedColors; + local array gradientColors; + local array gradientPoints; + local FormattingInfo targetInfo; if (colorTag.IsEmpty()) { Report(FSE_EmptyColorTag); return targetInfo; // not colored } - specifiedColors = colorTag.SplitByCharacter(separatorCharacter, true); + specifiedColors = colorTag.SplitByCharacter(separatorCharacter, true, true); for (i = 0; i < specifiedColors.length; i += 1) { colorParser = _.text.Parse(specifiedColors[i]); diff --git a/sources/Text/JSON/JSONPointer.uc b/sources/Text/JSON/JSONPointer.uc index 6e16898..3358714 100644 --- a/sources/Text/JSON/JSONPointer.uc +++ b/sources/Text/JSON/JSONPointer.uc @@ -92,16 +92,17 @@ public final function JSONPointer Empty() */ public final function JSONPointer Set(BaseText pointerAsText) { - local int i; - local bool hasEscapedSequences; - local Component nextComponent; - local array parts; + local int i; + local bool hasEscapedSequences; + local Component nextComponent; + local MutableText nextPart; + local array parts; Empty(); if (pointerAsText == none) { return self; } hasEscapedSequences = (pointerAsText.IndexOf(T(TJSON_ESCAPE)) >= 0); - parts = pointerAsText.SplitByCharacter(T(TSLASH).GetCharacter(0)); + parts = pointerAsText.SplitByCharacter(T(TSLASH).GetCharacter(0),, true); // First element of the array is expected to be empty, so throw it away; // If it is not empty - then `pointerAsText` does not start with "/" and // we will pretend that we have already removed first element, thus @@ -119,13 +120,14 @@ public final function JSONPointer Set(BaseText pointerAsText) // https://tools.ietf.org/html/rfc6901 for (i = 0; i < parts.length; i += 1) { - parts[i].Replace(T(TJSON_ESCAPED_SLASH), T(TSLASH)); - parts[i].Replace(T(TJSON_ESCAPED_ESCAPE), T(TJSON_ESCAPE)); + nextPart = MutableText(parts[i]); + nextPart.Replace(T(TJSON_ESCAPED_SLASH), T(TSLASH)); + nextPart.Replace(T(TJSON_ESCAPED_ESCAPE), T(TJSON_ESCAPE)); } } for (i = 0; i < parts.length; i += 1) { - nextComponent.asText = parts[i]; + nextComponent.asText = MutableText(parts[i]); components[components.length] = nextComponent; } return self; diff --git a/sources/Text/Tests/TEST_Parser.uc b/sources/Text/Tests/TEST_Parser.uc index c04a9ea..083a1db 100644 Binary files a/sources/Text/Tests/TEST_Parser.uc and b/sources/Text/Tests/TEST_Parser.uc differ diff --git a/sources/Text/Tests/TEST_Text.uc b/sources/Text/Tests/TEST_Text.uc index 8b0502c..ffa7c13 100644 Binary files a/sources/Text/Tests/TEST_Text.uc and b/sources/Text/Tests/TEST_Text.uc differ diff --git a/sources/Text/Tests/TEST_TextAPI.uc b/sources/Text/Tests/TEST_TextAPI.uc index e4b6968..bc339c7 100644 Binary files a/sources/Text/Tests/TEST_TextAPI.uc and b/sources/Text/Tests/TEST_TextAPI.uc differ diff --git a/sources/Text/TextAPI.uc b/sources/Text/TextAPI.uc index e356db2..9c87c53 100644 --- a/sources/Text/TextAPI.uc +++ b/sources/Text/TextAPI.uc @@ -628,12 +628,12 @@ public final function BaseText.Character ToUpper(BaseText.Character character) * @return Separated words. Empty array if passed `source` was empty, * otherwise contains at least one element. */ -public final function array Parts(BaseText source) +public final function array Parts(BaseText source) { - local array result; + local array result; if (source == none) return result; if (source.GetLength() <= 0) return result; - result = source.SplitByCharacter(source.GetCharacter(0)); + result = source.SplitByCharacter(source.GetCharacter(0),, true); // Since we use first character as a separator: // 1. `result` is guaranteed to be non-empty; // 2. We can just drop first (empty) substring. @@ -642,6 +642,31 @@ public final function array Parts(BaseText source) return result; } +/** + * Prepares an array of parts from a given single `BaseText`. + * First character is treated as a separator with which the rest of + * the given `BaseText` is split into parts: + * ~ "/ab/c/d" => ["ab", "c", "d"] + * ~ "zWordzomgzz" => ["Word", "omg", "", ""] + * + * This method is useful to easily prepare array of words for `Parser`'s + * methods. + * + * @param source `string` that contains separator with parts to + * separate and extract. + * @return Separated words. Empty array if passed `source` was empty, + * otherwise contains at least one element. + */ +public final function array PartsS(string source) +{ + local MutableText wrapper; + local array result; + wrapper = _.text.FromStringM(source); + result = Parts(wrapper); + _.memory.Free(wrapper); + return result; +} + /** * Creates a new, empty `MutableText`. *