diff --git a/AK/String.cpp b/AK/String.cpp index 44fd77fb70b..bf423b0c8a5 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -483,10 +483,7 @@ Optional String::find(char c, size_t start) const Optional String::find(StringView const& view, size_t start) const { - auto index = StringUtils::find(substring_view(start), view); - if (!index.has_value()) - return {}; - return index.value() + start; + return StringUtils::find(*this, view, start); } } diff --git a/AK/StringUtils.cpp b/AK/StringUtils.cpp index 5c5d5db10c9..fdc48301206 100644 --- a/AK/StringUtils.cpp +++ b/AK/StringUtils.cpp @@ -332,11 +332,34 @@ StringView trim_whitespace(const StringView& str, TrimMode mode) return trim(str, " \n\t\v\f\r", mode); } -Optional find(const StringView& haystack, const StringView& needle) +Optional find(StringView const& haystack, char needle, size_t start) { - return AK::memmem_optional( - haystack.characters_without_null_termination(), haystack.length(), + if (start >= haystack.length()) + return {}; + for (size_t i = start; i < haystack.length(); ++i) { + if (haystack[i] == needle) + return i; + } + return {}; +} + +Optional find(StringView const& haystack, StringView const& needle, size_t start) +{ + if (start > haystack.length()) + return {}; + auto index = AK::memmem_optional( + haystack.characters_without_null_termination() + start, haystack.length() - start, needle.characters_without_null_termination(), needle.length()); + return index.has_value() ? (*index + start) : index; +} + +Optional find_last(StringView const& haystack, char needle) +{ + for (size_t i = haystack.length(); i > 0; --i) { + if (haystack[i - 1] == needle) + return i - 1; + } + return {}; } String to_snakecase(const StringView& str) diff --git a/AK/StringUtils.h b/AK/StringUtils.h index fa7ae1902d6..f7211b05616 100644 --- a/AK/StringUtils.h +++ b/AK/StringUtils.h @@ -57,7 +57,12 @@ bool contains(const StringView&, const StringView&, CaseSensitivity); bool is_whitespace(const StringView&); StringView trim(const StringView& string, const StringView& characters, TrimMode mode); StringView trim_whitespace(const StringView& string, TrimMode mode); -Optional find(const StringView& haystack, const StringView& needle); + +Optional find(StringView const& haystack, char needle, size_t start = 0); +Optional find(StringView const& haystack, StringView const& needle, size_t start = 0); +Optional find_last(StringView const& haystack, char needle); +Vector find_all(StringView const& haystack, StringView const& needle); + String to_snakecase(const StringView&); } diff --git a/AK/StringView.cpp b/AK/StringView.cpp index 9053a6d1312..9960d667075 100644 --- a/AK/StringView.cpp +++ b/AK/StringView.cpp @@ -282,16 +282,6 @@ Optional StringView::find_last_of(const StringView& view) const return {}; } -Optional StringView::find(char c) const -{ - return find(StringView { &c, 1 }); -} - -Optional StringView::find(const StringView& view) const -{ - return StringUtils::find(*this, view); -} - String StringView::to_string() const { return String { *this }; } } diff --git a/AK/StringView.h b/AK/StringView.h index 356f65f8f20..1c4da712485 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -92,8 +92,10 @@ public: Optional find_last_of(char) const; Optional find_last_of(const StringView&) const; - Optional find(const StringView&) const; - Optional find(char c) const; + [[nodiscard]] Optional find(char needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } + [[nodiscard]] Optional find(StringView const& needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } + [[nodiscard]] Optional find_last(char needle) const { return StringUtils::find_last(*this, needle); } + // FIXME: Implement find_last(StringView const&) for API symmetry. [[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const {