summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2021-08-26 13:55:41 -0400
committerLinus Groh <mail@linusgroh.de>2021-08-26 22:04:09 +0100
commit262e4126346a650b442363887fe9683c56f71d1f (patch)
tree49d3bde5daa857fc0e6f76c6b7680a6d58055e4a
parentd2af27d2d046111f3828914257e2f4dff065e365 (diff)
downloadserenity-262e4126346a650b442363887fe9683c56f71d1f.zip
AK: Implement method to convert a String/StringView to title case
This implementation preserves consecutive spaces in the orginal string.
-rw-r--r--AK/String.cpp5
-rw-r--r--AK/String.h1
-rw-r--r--AK/StringUtils.cpp16
-rw-r--r--AK/StringUtils.h1
-rw-r--r--AK/StringView.cpp5
-rw-r--r--AK/StringView.h1
-rw-r--r--Tests/AK/TestStringUtils.cpp14
7 files changed, 43 insertions, 0 deletions
diff --git a/AK/String.cpp b/AK/String.cpp
index f6635f563f..dae488464c 100644
--- a/AK/String.cpp
+++ b/AK/String.cpp
@@ -446,6 +446,11 @@ String String::to_snakecase() const
return StringUtils::to_snakecase(*this);
}
+String String::to_titlecase() const
+{
+ return StringUtils::to_titlecase(*this);
+}
+
bool operator<(const char* characters, const String& string)
{
if (!characters)
diff --git a/AK/String.h b/AK/String.h
index e213ec3ebb..9bc3e5e2d1 100644
--- a/AK/String.h
+++ b/AK/String.h
@@ -120,6 +120,7 @@ public:
[[nodiscard]] String to_lowercase() const;
[[nodiscard]] String to_uppercase() const;
[[nodiscard]] String to_snakecase() const;
+ [[nodiscard]] String to_titlecase() const;
[[nodiscard]] bool is_whitespace() const { return StringUtils::is_whitespace(*this); }
diff --git a/AK/StringUtils.cpp b/AK/StringUtils.cpp
index 2c99617848..a73abfa09b 100644
--- a/AK/StringUtils.cpp
+++ b/AK/StringUtils.cpp
@@ -411,6 +411,22 @@ String to_snakecase(const StringView& str)
return builder.to_string();
}
+String to_titlecase(StringView const& str)
+{
+ StringBuilder builder;
+ bool next_is_upper = true;
+
+ for (auto ch : str) {
+ if (next_is_upper)
+ builder.append_code_point(to_ascii_uppercase(ch));
+ else
+ builder.append_code_point(to_ascii_lowercase(ch));
+ next_is_upper = ch == ' ';
+ }
+
+ return builder.to_string();
+}
+
}
}
diff --git a/AK/StringUtils.h b/AK/StringUtils.h
index f123665fd2..df1c13b13b 100644
--- a/AK/StringUtils.h
+++ b/AK/StringUtils.h
@@ -69,6 +69,7 @@ enum class SearchDirection {
Optional<size_t> find_any_of(StringView const& haystack, StringView const& needles, SearchDirection);
String to_snakecase(const StringView&);
+String to_titlecase(StringView const&);
}
diff --git a/AK/StringView.cpp b/AK/StringView.cpp
index b742864671..0aeb124676 100644
--- a/AK/StringView.cpp
+++ b/AK/StringView.cpp
@@ -183,6 +183,11 @@ String StringView::to_uppercase_string() const
return StringImpl::create_uppercased(characters_without_null_termination(), length());
}
+String StringView::to_titlecase_string() const
+{
+ return StringUtils::to_titlecase(*this);
+}
+
StringView StringView::substring_view_starting_from_substring(const StringView& substring) const
{
const char* remaining_characters = substring.characters_without_null_termination();
diff --git a/AK/StringView.h b/AK/StringView.h
index 0d25fec81b..f98b18ff55 100644
--- a/AK/StringView.h
+++ b/AK/StringView.h
@@ -85,6 +85,7 @@ public:
[[nodiscard]] String to_lowercase_string() const;
[[nodiscard]] String to_uppercase_string() const;
+ [[nodiscard]] String to_titlecase_string() const;
[[nodiscard]] Optional<size_t> find(char needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); }
[[nodiscard]] Optional<size_t> find(StringView const& needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); }
diff --git a/Tests/AK/TestStringUtils.cpp b/Tests/AK/TestStringUtils.cpp
index 315c14f1da..948adde861 100644
--- a/Tests/AK/TestStringUtils.cpp
+++ b/Tests/AK/TestStringUtils.cpp
@@ -304,3 +304,17 @@ TEST_CASE(to_snakecase)
EXPECT_EQ(AK::StringUtils::to_snakecase("FBar"), "f_bar");
EXPECT_EQ(AK::StringUtils::to_snakecase("FooB"), "foo_b");
}
+
+TEST_CASE(to_titlecase)
+{
+ EXPECT_EQ(AK::StringUtils::to_titlecase(""sv), ""sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("f"sv), "F"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("foobar"sv), "Foobar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("Foobar"sv), "Foobar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("FOOBAR"sv), "Foobar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("foo bar"sv), "Foo Bar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("foo bAR"sv), "Foo Bar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("foo bar"sv), "Foo Bar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase("foo bar"sv), "Foo Bar"sv);
+ EXPECT_EQ(AK::StringUtils::to_titlecase(" foo bar "sv), " Foo Bar "sv);
+}