mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
AK: Add a StringView method to count the number of lines in a string
We already have a helper to split a StringView by line while considering "\n", "\r", and "\r\n". Add an analagous method to just count the number of lines in the same manner.
This commit is contained in:
parent
07a27b2ec0
commit
82ea53cf10
Notes:
sideshowbarker
2024-07-17 01:10:58 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/82ea53cf10 Pull-request: https://github.com/SerenityOS/serenity/pull/23525 Reviewed-by: https://github.com/LucasChollet ✅
3 changed files with 79 additions and 30 deletions
|
@ -68,6 +68,48 @@ Vector<StringView> StringView::split_view(StringView separator, SplitBehavior sp
|
|||
return parts;
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
static void for_each_line(StringView string, Callback&& callback)
|
||||
{
|
||||
char const* characters = string.characters_without_null_termination();
|
||||
|
||||
size_t substart = 0;
|
||||
bool last_ch_was_cr = false;
|
||||
|
||||
for (size_t i = 0; i < string.length(); ++i) {
|
||||
char ch = characters[i];
|
||||
bool split_view = false;
|
||||
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
if (last_ch_was_cr)
|
||||
substart = i + 1;
|
||||
else
|
||||
split_view = true;
|
||||
|
||||
last_ch_was_cr = false;
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
split_view = true;
|
||||
last_ch_was_cr = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
last_ch_was_cr = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (split_view) {
|
||||
callback(string.substring_view(substart, i - substart));
|
||||
substart = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (size_t taillen = string.length() - substart; taillen != 0)
|
||||
callback(string.substring_view(substart, taillen));
|
||||
}
|
||||
|
||||
Vector<StringView> StringView::lines(ConsiderCarriageReturn consider_carriage_return) const
|
||||
{
|
||||
if (is_empty())
|
||||
|
@ -76,36 +118,24 @@ Vector<StringView> StringView::lines(ConsiderCarriageReturn consider_carriage_re
|
|||
if (consider_carriage_return == ConsiderCarriageReturn::No)
|
||||
return split_view('\n', SplitBehavior::KeepEmpty);
|
||||
|
||||
Vector<StringView> v;
|
||||
size_t substart = 0;
|
||||
bool last_ch_was_cr = false;
|
||||
bool split_view = false;
|
||||
for (size_t i = 0; i < length(); ++i) {
|
||||
char ch = characters_without_null_termination()[i];
|
||||
if (ch == '\n') {
|
||||
split_view = true;
|
||||
if (last_ch_was_cr) {
|
||||
substart = i + 1;
|
||||
split_view = false;
|
||||
}
|
||||
}
|
||||
if (ch == '\r') {
|
||||
split_view = true;
|
||||
last_ch_was_cr = true;
|
||||
} else {
|
||||
last_ch_was_cr = false;
|
||||
}
|
||||
if (split_view) {
|
||||
size_t sublen = i - substart;
|
||||
v.append(substring_view(substart, sublen));
|
||||
substart = i + 1;
|
||||
}
|
||||
split_view = false;
|
||||
}
|
||||
size_t taillen = length() - substart;
|
||||
if (taillen != 0)
|
||||
v.append(substring_view(substart, taillen));
|
||||
return v;
|
||||
Vector<StringView> lines;
|
||||
for_each_line(*this, [&](auto line) { lines.append(line); });
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
size_t StringView::count_lines(ConsiderCarriageReturn consider_carriage_return) const
|
||||
{
|
||||
if (is_empty())
|
||||
return 1;
|
||||
|
||||
if (consider_carriage_return == ConsiderCarriageReturn::No)
|
||||
return count('\n') + 1;
|
||||
|
||||
size_t lines = 0;
|
||||
for_each_line(*this, [&](auto) { ++lines; });
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
bool StringView::starts_with(char ch) const
|
||||
|
|
|
@ -240,6 +240,7 @@ public:
|
|||
Yes,
|
||||
};
|
||||
[[nodiscard]] Vector<StringView> lines(ConsiderCarriageReturn = ConsiderCarriageReturn::Yes) const;
|
||||
[[nodiscard]] size_t count_lines(ConsiderCarriageReturn = ConsiderCarriageReturn::Yes) const;
|
||||
|
||||
// Create a new substring view of this string view, starting either at the beginning of
|
||||
// the given substring view, or after its end, and continuing until the end of this string
|
||||
|
|
|
@ -105,6 +105,24 @@ TEST_CASE(lines)
|
|||
EXPECT_EQ(test_string_vector.at(2).is_empty(), true);
|
||||
}
|
||||
|
||||
TEST_CASE(count_lines)
|
||||
{
|
||||
EXPECT_EQ(""sv.count_lines(), 1u);
|
||||
EXPECT_EQ("foo"sv.count_lines(), 1u);
|
||||
|
||||
EXPECT_EQ("foo\nbar"sv.count_lines(), 2u);
|
||||
EXPECT_EQ("foo\rbar"sv.count_lines(), 2u);
|
||||
EXPECT_EQ("foo\rbar"sv.count_lines(StringView::ConsiderCarriageReturn::No), 1u);
|
||||
EXPECT_EQ("foo\r\nbar"sv.count_lines(), 2u);
|
||||
EXPECT_EQ("foo\r\nbar"sv.count_lines(StringView::ConsiderCarriageReturn::No), 2u);
|
||||
|
||||
EXPECT_EQ("foo\nbar\nbax"sv.count_lines(), 3u);
|
||||
EXPECT_EQ("foo\rbar\rbaz"sv.count_lines(), 3u);
|
||||
EXPECT_EQ("foo\rbar\rbaz"sv.count_lines(StringView::ConsiderCarriageReturn::No), 1u);
|
||||
EXPECT_EQ("foo\r\nbar\r\nbaz"sv.count_lines(), 3u);
|
||||
EXPECT_EQ("foo\r\nbar\r\nbaz"sv.count_lines(StringView::ConsiderCarriageReturn::No), 3u);
|
||||
}
|
||||
|
||||
TEST_CASE(find)
|
||||
{
|
||||
auto test_string_view = "aabbcc_xy_ccbbaa"sv;
|
||||
|
|
Loading…
Reference in a new issue