From 8a47a12207348ad332c4ed5987c0ba432ff5de5a Mon Sep 17 00:00:00 2001 From: kobewi Date: Fri, 12 Aug 2022 16:21:15 +0200 Subject: Add support for empty delimiter in String.split --- core/string/ustring.cpp | 21 +++++++++++++++++---- core/string/ustring.h | 4 ++-- core/variant/variant_call.cpp | 4 ++-- doc/classes/String.xml | 8 ++++---- tests/core/string/test_string.h | 8 ++++++++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index c86c8316fe..c6cc4cc4ac 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1180,9 +1180,14 @@ Vector String::split(const String &p_splitter, bool p_allow_empty, int p int len = length(); while (true) { - int end = find(p_splitter, from); - if (end < 0) { - end = len; + int end; + if (p_splitter.is_empty()) { + end = from + 1; + } else { + end = find(p_splitter, from); + if (end < 0) { + end = len; + } } if (p_allow_empty || (end > from)) { if (p_maxsplit <= 0) { @@ -1223,7 +1228,15 @@ Vector String::rsplit(const String &p_splitter, bool p_allow_empty, int break; } - int left_edge = rfind(p_splitter, remaining_len - p_splitter.length()); + int left_edge; + if (p_splitter.is_empty()) { + left_edge = remaining_len - 1; + if (left_edge == 0) { + left_edge--; // Skip to the < 0 condition. + } + } else { + left_edge = rfind(p_splitter, remaining_len - p_splitter.length()); + } if (left_edge < 0) { // no more splitters, we're done diff --git a/core/string/ustring.h b/core/string/ustring.h index 4b6568a502..8af74584f3 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -345,8 +345,8 @@ public: String get_slice(String p_splitter, int p_slice) const; String get_slicec(char32_t p_splitter, int p_slice) const; - Vector split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; - Vector rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; + Vector split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; + Vector rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; Vector split_spaces() const; Vector split_floats(const String &p_splitter, bool p_allow_empty = true) const; Vector split_floats_mk(const Vector &p_splitters, bool p_allow_empty = true) const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 7da46a2d05..91af2bab85 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1509,8 +1509,8 @@ static void _register_variant_builtin_methods() { bind_method(String, to_camel_case, sarray(), varray()); bind_method(String, to_pascal_case, sarray(), varray()); bind_method(String, to_snake_case, sarray(), varray()); - bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0)); - bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0)); + bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); + bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true)); bind_method(String, join, sarray("parts"), varray()); diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 1ee91b91d2..b0b4f74b46 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -634,11 +634,11 @@ - + - Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right. + Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right. If [param delimiter] is an empty string, each substring will be a single character. The splits in the returned array are sorted in the same order as the original string, from left to right. If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. If [param maxsplit] is specified, it defines the number of splits to do from the right up to [param maxsplit]. The default value of 0 means that all items are split, thus giving the same result as [method split]. @@ -710,11 +710,11 @@ - + - Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length. + Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length. If [param delimiter] is an empty string, each substring will be a single character. If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. If [param maxsplit] is specified, it defines the number of splits to do from the left up to [param maxsplit]. The default value of [code]0[/code] means that all items are split. If you need only one element from the array at a specific index, [method get_slice] is a more performant option. diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index cd1b421ce8..7e4e3aa9f0 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -485,6 +485,7 @@ TEST_CASE("[String] Splitting") { const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" }; const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" }; + const char *slices_3[4] = { "t", "e", "s", "t" }; l = s.split(",", true, 2); CHECK(l.size() == 3); @@ -498,6 +499,13 @@ TEST_CASE("[String] Splitting") { CHECK(l[i] == slices_r[i]); } + s = "test"; + l = s.split(); + CHECK(l.size() == 4); + for (int i = 0; i < l.size(); i++) { + CHECK(l[i] == slices_3[i]); + } + s = "Mars Jupiter Saturn Uranus"; const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" }; l = s.split_spaces(); -- cgit v1.2.3