71 lines
1.5 KiB
C++
71 lines
1.5 KiB
C++
|
#include <aocpp/Startup.hpp>
|
||
|
#include <doctest.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cstddef>
|
||
|
#include <stdexcept>
|
||
|
#include <string_view>
|
||
|
|
||
|
auto rem_chars(std::string_view const str) -> std::size_t
|
||
|
{
|
||
|
std::size_t result = 2; // two outer quotes
|
||
|
auto cursor = begin(str);
|
||
|
while (cursor != end(str))
|
||
|
{
|
||
|
if (*cursor++ == '\\')
|
||
|
{
|
||
|
if (cursor == end(str))
|
||
|
throw std::runtime_error{"bad input"};
|
||
|
auto const width = *cursor == 'x' ? 3 : 1;
|
||
|
result += width;
|
||
|
cursor += width;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
auto needs_escape(char const c) -> bool
|
||
|
{
|
||
|
return c == '\\' || c == '"';
|
||
|
};
|
||
|
|
||
|
auto add_chars(std::string_view const str) -> std::size_t
|
||
|
{
|
||
|
return 2 + std::count_if(begin(str), end(str), needs_escape);
|
||
|
}
|
||
|
|
||
|
TEST_SUITE("documented examples") {
|
||
|
using namespace std::string_view_literals;
|
||
|
|
||
|
TEST_CASE("part 1") {
|
||
|
REQUIRE(2 == rem_chars(R"("")"sv));
|
||
|
REQUIRE(2 == rem_chars(R"("abc")"sv));
|
||
|
REQUIRE(3 == rem_chars(R"("aaa\"aaa")"sv));
|
||
|
REQUIRE(5 == rem_chars(R"("\x27")"sv));
|
||
|
}
|
||
|
|
||
|
TEST_CASE("part 2") {
|
||
|
REQUIRE(4 == add_chars(R"("")"));
|
||
|
REQUIRE(4 == add_chars(R"("abc")"sv));
|
||
|
REQUIRE(6 == add_chars(R"("aaa\"aaa")"sv));
|
||
|
REQUIRE(5 == add_chars(R"("\x27")"sv));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
auto Main(std::istream &in, std::ostream &out) -> void
|
||
|
{
|
||
|
std::string line;
|
||
|
std::size_t part1 = 0;
|
||
|
std::size_t part2 = 0;
|
||
|
|
||
|
while (std::getline(in, line))
|
||
|
{
|
||
|
part1 += rem_chars(line);
|
||
|
part2 += add_chars(line);
|
||
|
}
|
||
|
|
||
|
out << "Part 1: " << part1 << std::endl;
|
||
|
out << "Part 2: " << part2 << std::endl;
|
||
|
}
|