diff --git a/AK/String.cpp b/AK/String.cpp index bf423b0c8a5..d82f6ab8b41 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -293,23 +293,6 @@ bool String::equals_ignoring_case(const StringView& other) const return StringUtils::equals_ignoring_case(view(), other); } -Vector String::find_all(const String& needle) const -{ - Vector positions; - size_t start = 0, pos; - for (;;) { - const char* ptr = strstr(characters() + start, needle.characters()); - if (!ptr) - break; - - pos = ptr - characters(); - positions.append(pos); - - start = pos + 1; - } - return positions; -} - int String::replace(const String& needle, const String& replacement, bool all_occurrences) { if (is_empty()) diff --git a/AK/String.h b/AK/String.h index a3e70ba8034..6037e478ec2 100644 --- a/AK/String.h +++ b/AK/String.h @@ -143,6 +143,7 @@ public: [[nodiscard]] Optional find(char, size_t start = 0) const; [[nodiscard]] Optional find(StringView const&, size_t start = 0) const; + [[nodiscard]] Vector find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); } [[nodiscard]] String substring(size_t start) const; [[nodiscard]] String substring(size_t start, size_t length) const; @@ -279,7 +280,6 @@ public: int replace(const String& needle, const String& replacement, bool all_occurrences = false); size_t count(const String& needle) const; - Vector find_all(const String& needle) const; [[nodiscard]] String reverse() const; template diff --git a/AK/StringUtils.cpp b/AK/StringUtils.cpp index fdc48301206..48bfb271498 100644 --- a/AK/StringUtils.cpp +++ b/AK/StringUtils.cpp @@ -362,6 +362,22 @@ Optional find_last(StringView const& haystack, char needle) return {}; } +Vector find_all(StringView const& haystack, StringView const& needle) +{ + Vector positions; + size_t current_position = 0; + while (current_position <= haystack.length()) { + auto maybe_position = AK::memmem_optional( + haystack.characters_without_null_termination() + current_position, haystack.length() - current_position, + needle.characters_without_null_termination(), needle.length()); + if (!maybe_position.has_value()) + break; + positions.append(current_position + *maybe_position); + current_position += *maybe_position + 1; + } + return positions; +} + String to_snakecase(const StringView& str) { auto should_insert_underscore = [&](auto i, auto current_char) { diff --git a/AK/StringView.h b/AK/StringView.h index 86a57cb94f3..7473ffa3ca5 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -91,6 +91,8 @@ public: [[nodiscard]] Optional find_last(char needle) const { return StringUtils::find_last(*this, needle); } // FIXME: Implement find_last(StringView const&) for API symmetry. + [[nodiscard]] Vector find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); } + [[nodiscard]] Optional find_first_of(StringView const&) const; [[nodiscard]] Optional find_last_of(StringView const&) const;