mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
AK: Add SplitBehavior::KeepTrailingSeparator with tests
This commit is contained in:
parent
3e8b5ac920
commit
7c33f8f7df
Notes:
sideshowbarker
2024-07-17 05:08:08 +09:00
Author: https://github.com/demostanis Commit: https://github.com/SerenityOS/serenity/commit/7c33f8f7df Pull-request: https://github.com/SerenityOS/serenity/pull/15750 Reviewed-by: https://github.com/AtkinsSJ Reviewed-by: https://github.com/davidot Reviewed-by: https://github.com/linusg ✅
5 changed files with 26 additions and 6 deletions
|
@ -110,12 +110,13 @@ Vector<String> String::split_limit(char separator, size_t limit, SplitBehavior s
|
||||||
Vector<String> v;
|
Vector<String> v;
|
||||||
size_t substart = 0;
|
size_t substart = 0;
|
||||||
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
|
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) {
|
for (size_t i = 0; i < length() && (v.size() + 1) != limit; ++i) {
|
||||||
char ch = characters()[i];
|
char ch = characters()[i];
|
||||||
if (ch == separator) {
|
if (ch == separator) {
|
||||||
size_t sublen = i - substart;
|
size_t sublen = i - substart;
|
||||||
if (sublen != 0 || keep_empty)
|
if (sublen != 0 || keep_empty)
|
||||||
v.append(substring(substart, sublen));
|
v.append(substring(substart, keep_separator ? sublen + 1 : sublen));
|
||||||
substart = i + 1;
|
substart = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,12 +134,13 @@ Vector<StringView> String::split_view(Function<bool(char)> separator, SplitBehav
|
||||||
Vector<StringView> v;
|
Vector<StringView> v;
|
||||||
size_t substart = 0;
|
size_t substart = 0;
|
||||||
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
|
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) {
|
for (size_t i = 0; i < length(); ++i) {
|
||||||
char ch = characters()[i];
|
char ch = characters()[i];
|
||||||
if (separator(ch)) {
|
if (separator(ch)) {
|
||||||
size_t sublen = i - substart;
|
size_t sublen = i - substart;
|
||||||
if (sublen != 0 || keep_empty)
|
if (sublen != 0 || keep_empty)
|
||||||
v.append(substring_view(substart, sublen));
|
v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
|
||||||
substart = i + 1;
|
substart = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,17 @@ enum class TrimWhitespace {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SplitBehavior : unsigned {
|
enum class SplitBehavior : unsigned {
|
||||||
|
// Neither keep empty substrings nor keep the trailing separator.
|
||||||
|
// This is the default behavior if unspecified.
|
||||||
Nothing = 0,
|
Nothing = 0,
|
||||||
|
|
||||||
// If two separators follow each other without any characters
|
// 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,
|
KeepEmpty = 1,
|
||||||
|
|
||||||
|
// Do not strip off the separator at the end of the string.
|
||||||
|
KeepTrailingSeparator = 2,
|
||||||
};
|
};
|
||||||
AK_ENUM_BITWISE_OPERATORS(SplitBehavior);
|
AK_ENUM_BITWISE_OPERATORS(SplitBehavior);
|
||||||
|
|
||||||
|
|
|
@ -272,12 +272,13 @@ Vector<StringView> StringView::split_view_if(Function<bool(char)> const& predica
|
||||||
Vector<StringView> v;
|
Vector<StringView> v;
|
||||||
size_t substart = 0;
|
size_t substart = 0;
|
||||||
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
|
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) {
|
for (size_t i = 0; i < length(); ++i) {
|
||||||
char ch = characters_without_null_termination()[i];
|
char ch = characters_without_null_termination()[i];
|
||||||
if (predicate(ch)) {
|
if (predicate(ch)) {
|
||||||
size_t sublen = i - substart;
|
size_t sublen = i - substart;
|
||||||
if (sublen != 0 || keep_empty)
|
if (sublen != 0 || keep_empty)
|
||||||
v.append(substring_view(substart, sublen));
|
v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
|
||||||
substart = i + 1;
|
substart = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,11 +170,16 @@ public:
|
||||||
|
|
||||||
auto maybe_separator_index = find(separator);
|
auto maybe_separator_index = find(separator);
|
||||||
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
|
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
|
||||||
|
bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
|
||||||
while (maybe_separator_index.has_value()) {
|
while (maybe_separator_index.has_value()) {
|
||||||
auto separator_index = maybe_separator_index.value();
|
auto separator_index = maybe_separator_index.value();
|
||||||
auto part_with_separator = view.substring_view(0, separator_index + separator.length());
|
auto part_with_separator = view.substring_view(0, separator_index + separator.length());
|
||||||
if (keep_empty || separator_index > 0)
|
if (keep_empty || separator_index > 0) {
|
||||||
callback(part_with_separator.substring_view(0, separator_index));
|
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);
|
view = view.substring_view_starting_after_substring(part_with_separator);
|
||||||
maybe_separator_index = view.find(separator);
|
maybe_separator_index = view.find(separator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, 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), 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 }));
|
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)
|
TEST_CASE(constexpr_stuff)
|
||||||
|
|
Loading…
Reference in a new issue