Browse Source

Merge pull request #64321 from KoBeWi/s_p_l_i_t

Add support for empty delimiter in `String.split()`
Rémi Verschelde 2 years ago
parent
commit
1836b4b798

+ 17 - 4
core/string/ustring.cpp

@@ -1180,9 +1180,14 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
 	int len = length();
 	int len = length();
 
 
 	while (true) {
 	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_allow_empty || (end > from)) {
 			if (p_maxsplit <= 0) {
 			if (p_maxsplit <= 0) {
@@ -1223,7 +1228,15 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
 			break;
 			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) {
 		if (left_edge < 0) {
 			// no more splitters, we're done
 			// no more splitters, we're done

+ 2 - 2
core/string/ustring.h

@@ -345,8 +345,8 @@ public:
 	String get_slice(String p_splitter, int p_slice) const;
 	String get_slice(String p_splitter, int p_slice) const;
 	String get_slicec(char32_t p_splitter, int p_slice) const;
 	String get_slicec(char32_t p_splitter, int p_slice) const;
 
 
-	Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
-	Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
+	Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
+	Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
 	Vector<String> split_spaces() const;
 	Vector<String> split_spaces() const;
 	Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
 	Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
 	Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
 	Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;

+ 2 - 2
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_camel_case, sarray(), varray());
 	bind_method(String, to_pascal_case, sarray(), varray());
 	bind_method(String, to_pascal_case, sarray(), varray());
 	bind_method(String, to_snake_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, split_floats, sarray("delimiter", "allow_empty"), varray(true));
 	bind_method(String, join, sarray("parts"), varray());
 	bind_method(String, join, sarray("parts"), varray());
 
 

+ 4 - 4
doc/classes/String.xml

@@ -634,11 +634,11 @@
 		</method>
 		</method>
 		<method name="rsplit" qualifiers="const">
 		<method name="rsplit" qualifiers="const">
 			<return type="PackedStringArray" />
 			<return type="PackedStringArray" />
-			<param index="0" name="delimiter" type="String" />
+			<param index="0" name="delimiter" type="String" default="&quot;&quot;" />
 			<param index="1" name="allow_empty" type="bool" default="true" />
 			<param index="1" name="allow_empty" type="bool" default="true" />
 			<param index="2" name="maxsplit" type="int" default="0" />
 			<param index="2" name="maxsplit" type="int" default="0" />
 			<description>
 			<description>
-				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.
 				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 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].
 				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 @@
 		</method>
 		</method>
 		<method name="split" qualifiers="const">
 		<method name="split" qualifiers="const">
 			<return type="PackedStringArray" />
 			<return type="PackedStringArray" />
-			<param index="0" name="delimiter" type="String" />
+			<param index="0" name="delimiter" type="String" default="&quot;&quot;" />
 			<param index="1" name="allow_empty" type="bool" default="true" />
 			<param index="1" name="allow_empty" type="bool" default="true" />
 			<param index="2" name="maxsplit" type="int" default="0" />
 			<param index="2" name="maxsplit" type="int" default="0" />
 			<description>
 			<description>
-				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 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 [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.
 				If you need only one element from the array at a specific index, [method get_slice] is a more performant option.

+ 8 - 0
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_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
 	const char *slices_r[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);
 	l = s.split(",", true, 2);
 	CHECK(l.size() == 3);
 	CHECK(l.size() == 3);
@@ -498,6 +499,13 @@ TEST_CASE("[String] Splitting") {
 		CHECK(l[i] == slices_r[i]);
 		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";
 	s = "Mars Jupiter Saturn Uranus";
 	const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
 	const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
 	l = s.split_spaces();
 	l = s.split_spaces();