diff --git a/AK/String.h b/AK/String.h index d100cb14b85..6d1af1945e7 100644 --- a/AK/String.h +++ b/AK/String.h @@ -122,6 +122,8 @@ public: String to_lowercase() const; String to_uppercase() const; + bool is_whitespace() const { return StringUtils::is_whitespace(*this); } + #ifndef KERNEL String trim_whitespace(TrimMode mode = TrimMode::Both) const { diff --git a/AK/StringUtils.cpp b/AK/StringUtils.cpp index 993704109cf..239b3156d08 100644 --- a/AK/StringUtils.cpp +++ b/AK/StringUtils.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace AK { @@ -302,17 +303,17 @@ bool contains(const StringView& str, const StringView& needle, CaseSensitivity c return false; } +bool is_whitespace(const StringView& str) +{ + for (auto ch : str) { + if (!isspace(ch)) + return false; + } + return true; +} + StringView trim_whitespace(const StringView& str, TrimMode mode) { - auto is_whitespace_character = [](char ch) -> bool { - return ch == '\t' - || ch == '\n' - || ch == '\v' - || ch == '\f' - || ch == '\r' - || ch == ' '; - }; - size_t substring_start = 0; size_t substring_length = str.length(); @@ -320,7 +321,7 @@ StringView trim_whitespace(const StringView& str, TrimMode mode) for (size_t i = 0; i < str.length(); ++i) { if (substring_length == 0) return ""; - if (!is_whitespace_character(str[i])) + if (!isspace(str[i])) break; ++substring_start; --substring_length; @@ -331,7 +332,7 @@ StringView trim_whitespace(const StringView& str, TrimMode mode) for (size_t i = str.length() - 1; i > 0; --i) { if (substring_length == 0) return ""; - if (!is_whitespace_character(str[i])) + if (!isspace(str[i])) break; --substring_length; } diff --git a/AK/StringUtils.h b/AK/StringUtils.h index e2b5e4430dd..e32c5126950 100644 --- a/AK/StringUtils.h +++ b/AK/StringUtils.h @@ -69,6 +69,7 @@ bool equals_ignoring_case(const StringView&, const StringView&); bool ends_with(const StringView& a, const StringView& b, CaseSensitivity); bool starts_with(const StringView&, const StringView&, CaseSensitivity); bool contains(const StringView&, const StringView&, CaseSensitivity); +bool is_whitespace(const StringView&); StringView trim_whitespace(const StringView&, TrimMode mode); } diff --git a/AK/StringView.h b/AK/StringView.h index 1b90b7ba815..ee688bff564 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -180,6 +180,8 @@ public: String to_string() const; + bool is_whitespace() const { return StringUtils::is_whitespace(*this); } + template bool is_one_of(const T& string, Rest... rest) const { diff --git a/AK/Tests/TestStringUtils.cpp b/AK/Tests/TestStringUtils.cpp index 6d1d0c52ba0..abb6891144f 100644 --- a/AK/Tests/TestStringUtils.cpp +++ b/AK/Tests/TestStringUtils.cpp @@ -287,4 +287,15 @@ TEST_CASE(contains) EXPECT(!AK::StringUtils::contains(test_string, "L", CaseSensitivity::CaseInsensitive)); } +TEST_CASE(is_whitespace) +{ + EXPECT(AK::StringUtils::is_whitespace("")); + EXPECT(AK::StringUtils::is_whitespace(" ")); + EXPECT(AK::StringUtils::is_whitespace(" \t")); + EXPECT(AK::StringUtils::is_whitespace(" \t\n")); + EXPECT(AK::StringUtils::is_whitespace(" \t\n\r\v")); + EXPECT(!AK::StringUtils::is_whitespace(" a ")); + EXPECT(!AK::StringUtils::is_whitespace("a\t")); +} + TEST_MAIN(StringUtils)