diff --git a/AK/StringView.cpp b/AK/StringView.cpp index a08d31ff945..50a4c3b677a 100644 --- a/AK/StringView.cpp +++ b/AK/StringView.cpp @@ -31,7 +31,6 @@ #include #include #include -#include namespace AK { diff --git a/AK/StringView.h b/AK/StringView.h index 3fa71bf85f4..ae8e5a7a47c 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -32,6 +32,7 @@ #include #include #include +#include namespace AK { @@ -108,6 +109,29 @@ public: [[nodiscard]] Vector split_view(char, bool keep_empty = false) const; [[nodiscard]] Vector split_view(const StringView&, bool keep_empty = false) const; + template + [[nodiscard]] Vector split_view_if(UnaryPredicate&& predicate, bool keep_empty = false) const + { + if (is_empty()) + return {}; + + Vector v; + size_t substart = 0; + 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)); + substart = i + 1; + } + } + size_t taillen = length() - substart; + if (taillen != 0 || keep_empty) + v.append(substring_view(substart, taillen)); + return v; + } + // Create a Vector of StringViews split by line endings. As of CommonMark // 0.29, the spec defines a line ending as "a newline (U+000A), a carriage // return (U+000D) not followed by a newline, or a carriage return and a diff --git a/AK/Tests/TestStringView.cpp b/AK/Tests/TestStringView.cpp index a95be835bde..3a690700732 100644 --- a/AK/Tests/TestStringView.cpp +++ b/AK/Tests/TestStringView.cpp @@ -183,6 +183,13 @@ TEST_CASE(split_view) test_string_view = "axxbcxxdxx"; EXPECT_EQ(test_string_view.split_view("xx"), Vector({ "a", "bc", "d" })); EXPECT_EQ(test_string_view.split_view("xx", true), Vector({ "a", "bc", "d", "" })); + + test_string_view = "ax_b_cxd"; + auto predicate = [](char ch) { return ch == 'x' || ch == '_'; }; + EXPECT_EQ(test_string_view.split_view_if(predicate), Vector({ "a", "b", "c", "d" })); + EXPECT_EQ(test_string_view.split_view_if(predicate, true), Vector({ "a", "", "b", "c", "d" })); + EXPECT_EQ(test_string_view.split_view_if(predicate), Vector({ "a", "b", "c", "d" })); + EXPECT_EQ(test_string_view.split_view_if(predicate, true), Vector({ "a", "", "b", "c", "d" })); } TEST_MAIN(StringView)