浏览代码

AK: Add `split()` for `String`

martinfalisse 2 年之前
父节点
当前提交
aec2dadfdd
共有 3 个文件被更改,包括 54 次插入0 次删除
  1. 30 0
      AK/String.cpp
  2. 4 0
      AK/String.h
  3. 20 0
      Tests/AK/TestString.cpp

+ 30 - 0
AK/String.cpp

@@ -251,6 +251,36 @@ ErrorOr<String> String::vformatted(StringView fmtstr, TypeErasedFormatParams& pa
     return builder.to_string();
 }
 
+ErrorOr<Vector<String>> String::split(u32 separator, SplitBehavior split_behavior) const
+{
+    return split_limit(separator, 0, split_behavior);
+}
+
+ErrorOr<Vector<String>> String::split_limit(u32 separator, size_t limit, SplitBehavior split_behavior) const
+{
+    Vector<String> result;
+
+    if (is_empty())
+        return result;
+
+    bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
+
+    size_t substring_start = 0;
+    for (auto it = code_points().begin(); it != code_points().end() && (result.size() + 1) != limit; ++it) {
+        u32 code_point = *it;
+        if (code_point == separator) {
+            size_t substring_length = code_points().iterator_offset(it) - substring_start;
+            if (substring_length != 0 || keep_empty)
+                TRY(result.try_append(TRY(substring_from_byte_offset_with_shared_superstring(substring_start, substring_length))));
+            substring_start = code_points().iterator_offset(it) + it.underlying_code_point_length_in_bytes();
+        }
+    }
+    size_t tail_length = code_points().byte_length() - substring_start;
+    if (tail_length != 0 || keep_empty)
+        TRY(result.try_append(TRY(substring_from_byte_offset_with_shared_superstring(substring_start, tail_length))));
+    return result;
+}
+
 bool String::operator==(String const& other) const
 {
     if (is_short_string())

+ 4 - 0
AK/String.h

@@ -16,6 +16,7 @@
 #include <AK/StringView.h>
 #include <AK/Traits.h>
 #include <AK/Types.h>
+#include <AK/Vector.h>
 
 namespace AK {
 
@@ -101,6 +102,9 @@ public:
     ErrorOr<String> replace(StringView needle, StringView replacement, ReplaceMode replace_mode) const;
     ErrorOr<String> reverse() const;
 
+    [[nodiscard]] ErrorOr<Vector<String>> split_limit(u32 separator, size_t limit, SplitBehavior = SplitBehavior::Nothing) const;
+    [[nodiscard]] ErrorOr<Vector<String>> split(u32 separator, SplitBehavior = SplitBehavior::Nothing) const;
+
     [[nodiscard]] bool operator==(String const&) const;
     [[nodiscard]] bool operator!=(String const& other) const { return !(*this == other); }
 

+ 20 - 0
Tests/AK/TestString.cpp

@@ -272,3 +272,23 @@ TEST_CASE(is_one_of)
     EXPECT(bar.is_one_of("bar"sv, "foo"sv));
     EXPECT(bar.is_one_of("bar"sv));
 }
+
+TEST_CASE(split)
+{
+    {
+        auto test = MUST(String::from_utf8("foo bar baz"sv));
+        auto parts = MUST(test.split(' '));
+        EXPECT_EQ(parts.size(), 3u);
+        EXPECT_EQ(parts[0], "foo");
+        EXPECT_EQ(parts[1], "bar");
+        EXPECT_EQ(parts[2], "baz");
+    }
+    {
+        auto test = MUST(String::from_utf8("ωΣ2ωΣω"sv));
+        auto parts = MUST(test.split(0x03A3u));
+        EXPECT_EQ(parts.size(), 3u);
+        EXPECT_EQ(parts[0], "ω"sv);
+        EXPECT_EQ(parts[1], "2ω"sv);
+        EXPECT_EQ(parts[2], "ω"sv);
+    }
+}