summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordemostanis <demostanis@protonmail.com>2022-10-22 16:31:59 +0200
committerLinus Groh <mail@linusgroh.de>2022-10-24 23:29:18 +0100
commit7c33f8f7df321e2406f324f9aaa3890620a192e5 (patch)
treed3a7059d254b78456d0b3c1de81dc65542ec33bd
parent3e8b5ac92012e19847e536a20a3f0ec7e5c787d3 (diff)
downloadserenity-7c33f8f7df321e2406f324f9aaa3890620a192e5.zip
AK: Add SplitBehavior::KeepTrailingSeparator with tests
-rw-r--r--AK/String.cpp6
-rw-r--r--AK/StringUtils.h9
-rw-r--r--AK/StringView.cpp3
-rw-r--r--AK/StringView.h9
-rw-r--r--Tests/AK/TestStringView.cpp5
5 files changed, 26 insertions, 6 deletions
diff --git a/AK/String.cpp b/AK/String.cpp
index 2497e8c8b4..3c63b70b62 100644
--- a/AK/String.cpp
+++ b/AK/String.cpp
@@ -110,12 +110,13 @@ Vector<String> String::split_limit(char separator, size_t limit, SplitBehavior s
Vector<String> v;
size_t substart = 0;
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
+ bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
for (size_t i = 0; i < length() && (v.size() + 1) != limit; ++i) {
char ch = characters()[i];
if (ch == separator) {
size_t sublen = i - substart;
if (sublen != 0 || keep_empty)
- v.append(substring(substart, sublen));
+ v.append(substring(substart, keep_separator ? sublen + 1 : sublen));
substart = i + 1;
}
}
@@ -133,12 +134,13 @@ Vector<StringView> String::split_view(Function<bool(char)> separator, SplitBehav
Vector<StringView> v;
size_t substart = 0;
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
+ bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
for (size_t i = 0; i < length(); ++i) {
char ch = characters()[i];
if (separator(ch)) {
size_t sublen = i - substart;
if (sublen != 0 || keep_empty)
- v.append(substring_view(substart, sublen));
+ v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
substart = i + 1;
}
}
diff --git a/AK/StringUtils.h b/AK/StringUtils.h
index 60dde9c359..883196ecfb 100644
--- a/AK/StringUtils.h
+++ b/AK/StringUtils.h
@@ -40,10 +40,17 @@ enum class TrimWhitespace {
};
enum class SplitBehavior : unsigned {
+ // Neither keep empty substrings nor keep the trailing separator.
+ // This is the default behavior if unspecified.
Nothing = 0,
+
// If two separators follow each other without any characters
- // in between, keep a "" in the resulting vector.
+ // in between, keep a "" in the resulting vector. (or only the
+ // separator if KeepTrailingSeparator is used)
KeepEmpty = 1,
+
+ // Do not strip off the separator at the end of the string.
+ KeepTrailingSeparator = 2,
};
AK_ENUM_BITWISE_OPERATORS(SplitBehavior);
diff --git a/AK/StringView.cpp b/AK/StringView.cpp
index 1b906d7970..3840e7c7f5 100644
--- a/AK/StringView.cpp
+++ b/AK/StringView.cpp
@@ -272,12 +272,13 @@ Vector<StringView> StringView::split_view_if(Function<bool(char)> const& predica
Vector<StringView> v;
size_t substart = 0;
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
+ bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
for (size_t i = 0; i < length(); ++i) {
char ch = characters_without_null_termination()[i];
if (predicate(ch)) {
size_t sublen = i - substart;
if (sublen != 0 || keep_empty)
- v.append(substring_view(substart, sublen));
+ v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
substart = i + 1;
}
}
diff --git a/AK/StringView.h b/AK/StringView.h
index e9d58c3198..8e65691e5a 100644
--- a/AK/StringView.h
+++ b/AK/StringView.h
@@ -170,11 +170,16 @@ public:
auto maybe_separator_index = find(separator);
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
+ bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
while (maybe_separator_index.has_value()) {
auto separator_index = maybe_separator_index.value();
auto part_with_separator = view.substring_view(0, separator_index + separator.length());
- if (keep_empty || separator_index > 0)
- callback(part_with_separator.substring_view(0, separator_index));
+ if (keep_empty || separator_index > 0) {
+ if (keep_separator)
+ callback(part_with_separator);
+ else
+ callback(part_with_separator.substring_view(0, separator_index));
+ }
view = view.substring_view_starting_after_substring(part_with_separator);
maybe_separator_index = view.find(separator);
}
diff --git a/Tests/AK/TestStringView.cpp b/Tests/AK/TestStringView.cpp
index 6aafffe82b..9d5bc18e0a 100644
--- a/Tests/AK/TestStringView.cpp
+++ b/Tests/AK/TestStringView.cpp
@@ -163,6 +163,11 @@ TEST_CASE(split_view)
EXPECT_EQ(test_string_view.split_view_if(predicate, SplitBehavior::KeepEmpty), Vector({ "a"sv, ""sv, "b"sv, "c"sv, "d"sv }));
EXPECT_EQ(test_string_view.split_view_if(predicate), Vector({ "a"sv, "b"sv, "c"sv, "d"sv }));
EXPECT_EQ(test_string_view.split_view_if(predicate, SplitBehavior::KeepEmpty), Vector({ "a"sv, ""sv, "b"sv, "c"sv, "d"sv }));
+
+ test_string_view = "a,,,b"sv;
+ EXPECT_EQ(test_string_view.split_view(","sv, SplitBehavior::KeepEmpty), Vector({ "a"sv, ""sv, ""sv, "b"sv }));
+ EXPECT_EQ(test_string_view.split_view(","sv, SplitBehavior::KeepTrailingSeparator), Vector({ "a,"sv, "b"sv }));
+ EXPECT_EQ(test_string_view.split_view(","sv, SplitBehavior::KeepTrailingSeparator | SplitBehavior::KeepEmpty), Vector({ "a,"sv, ","sv, ","sv, "b"sv }));
}
TEST_CASE(constexpr_stuff)