Merge pull request #64321 from KoBeWi/s_p_l_i_t

Add support for empty delimiter in `String.split()`
This commit is contained in:
Rémi Verschelde 2022-11-06 15:54:56 +01:00
commit 1836b4b798
No known key found for this signature in database
GPG key ID: C3336907360768E1
5 changed files with 33 additions and 12 deletions

View file

@ -1180,9 +1180,14 @@ Vector<String> 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> 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

View file

@ -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<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<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;

View file

@ -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());

View file

@ -634,11 +634,11 @@
</method>
<method name="rsplit" qualifiers="const">
<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="2" name="maxsplit" type="int" default="0" />
<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.
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 @@
</method>
<method name="split" qualifiers="const">
<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="2" name="maxsplit" type="int" default="0" />
<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 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.

View file

@ -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();