Skip to content

31.03.25 : 12.14 - 12.20 / 75 баллов / 08.04.25 23:59:59 #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ include_directories(shared)


##### subdirectories #####
set(DIRS week-W week-2 week-3 week-4 week-5 week-6 week-7 week-8 week-9 week-10 week-11)
set(DIRS week-W week-2 week-3 week-4 week-5 week-6 week-7 week-8 week-9 week-10 week-11 week-15)
foreach(DIR ${DIRS})
add_subdirectory(${DIR})
endforeach()
Expand Down
4 changes: 4 additions & 0 deletions week-15/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(DIRS task-12-14 task-12-15 task-12-20)
foreach(DIR ${DIRS})
add_subdirectory(${DIR})
endforeach()
3 changes: 3 additions & 0 deletions week-15/task-12-14/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_directories(include)

add_subdirectory(test)
16 changes: 16 additions & 0 deletions week-15/task-12-14/include/car_numbers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <algorithm>
#include <ranges>
#include <regex>
#include <string>
#include <vector>

std::vector<std::string> rus_car_numbers(const std::string& str) {
const std::regex pattern(R"(\b[ABEKMHOPCTYX]\d{3}[ABEKMHOPCTYX]{2}\b)");
std::vector<std::string> numbers;
std::ranges::for_each(std::sregex_iterator(std::cbegin(str), std::cend(str), pattern),
std::sregex_iterator(),
[&numbers](const auto& matches) { numbers.push_back(matches[0]); });
return numbers;
}
1 change: 1 addition & 0 deletions week-15/task-12-14/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp_test(test-12-14.cpp)
80 changes: 80 additions & 0 deletions week-15/task-12-14/test/test-12-14.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "car_numbers.hpp"
#include "gtest/gtest.h"

TEST(RusCarNumbersTest, EmptyInput) {
EXPECT_EQ(rus_car_numbers(""), std::vector<std::string>({}));
}

TEST(RusCarNumbersTest, NoNumbersInText) {
const std::string text = R"(
Just text without license plates.
Examples: 12345, ABCDEF, !@#$%^&*
Similar looking: AB12CD, X9Y9Z9
)";
EXPECT_EQ(rus_car_numbers(text), std::vector<std::string>({}));
}

TEST(RusCarNumbersTest, ValidNumbersWithoutRegion) {
const std::string text = R"(
Correct plates: A123BC, E555EE, K321AM
Parking spots: M111MM and T444YX
With trash: A123BC45 -> A123BC
Almost valid: X999XZ -> invalid (Z)
)";
EXPECT_EQ(rus_car_numbers(text), std::vector<std::string>({"A123BC", "E555EE", "K321AM",
"M111MM", "T444YX", "A123BC"}));
}

TEST(RusCarNumbersTest, InvalidFormats) {
const std::string text = R"(
Invalid:
ABC123 (wrong order)
123ABC (starts with digits)
A1B2C3 (alternating)
A123BC45 (with region, but takes A123BC)
A12BC (too short)
Z999ZZ (invalid letter Z)
)";
EXPECT_EQ(rus_car_numbers(text), std::vector<std::string>({"A123BC"}));
}

TEST(RusCarNumbersTest, MixedContent) {
const std::string text = R"(
Valid: A777BC and C666CT
Invalid: AB123C, X9Y9Z9
With region: T123TX42 -> T123TX
Trash: !Y222YA@
Almost valid: O999OI -> invalid (I)
)";
EXPECT_EQ(rus_car_numbers(text),
std::vector<std::string>({"A777BC", "C666CT", "T123TX", "Y222YA"}));
}

TEST(RusCarNumbersTest, EdgeCases) {
const std::string text = R"(
Edge cases:
A001AX (minimum)
X999XX (maximum)
B000TB (zeros in digits)
H555HH (same letters)
Almost valid:
A000AA0 (extra zero)
Y123YF (invalid F)
)";
EXPECT_EQ(rus_car_numbers(text),
std::vector<std::string>({"A001AX", "X999XX", "B000TB", "H555HH"}));
}

TEST(RusCarNumbersTest, AllValidLettersCombinations) {
const std::string text = R"(
All valid letters:
A123BC, B456TE, E789KX
K321AM, M111MO, H555OP
O999PC, P777CT, C666TY
T444YX, Y222XA, X888AB
)";
EXPECT_EQ(
rus_car_numbers(text),
std::vector<std::string>({"A123BC", "B456TE", "E789KX", "K321AM", "M111MO", "H555OP",
"O999PC", "P777CT", "C666TY", "T444YX", "Y222XA", "X888AB"}));
}
3 changes: 3 additions & 0 deletions week-15/task-12-15/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_directories(include)

add_subdirectory(test)
16 changes: 16 additions & 0 deletions week-15/task-12-15/include/emails.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <algorithm>
#include <ranges>
#include <regex>
#include <string>
#include <vector>

std::vector<std::string> emails(const std::string& str) {
const std::regex pattern(R"(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{1,}\b)");
std::vector<std::string> emails;
std::ranges::for_each(std::sregex_iterator(std::cbegin(str), std::cend(str), pattern),
std::sregex_iterator(),
[&emails](const auto& matches) { emails.push_back(matches[0]); });
return emails;
}
1 change: 1 addition & 0 deletions week-15/task-12-15/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp_test(test-12-15.cpp)
65 changes: 65 additions & 0 deletions week-15/task-12-15/test/test-12-15.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "emails.hpp"
#include "gtest/gtest.h"

TEST(EmailExtractionTest, EmptyInput) { EXPECT_EQ(emails(""), std::vector<std::string>({})); }

TEST(EmailExtractionTest, NoEmailsInText) {
const std::string text = R"(
This is just regular text without any emails.
Some symbols: @hello, test@, @test.com
Numbers: 12345, random!text
)";
EXPECT_EQ(emails(text), std::vector<std::string>({}));
}

TEST(EmailExtractionTest, ValidEmails) {
const std::string text = R"(
Contact us at: [email protected] or [email protected].
Student emails: [email protected], [email protected]
Special cases: [email protected], [email protected]
)";
EXPECT_EQ(emails(text),
std::vector<std::string>({"[email protected]", "[email protected]",
"[email protected]", "[email protected]",
"[email protected]", "[email protected]"}));
}

TEST(EmailExtractionTest, InvalidEmails) {
const std::string text = R"(
Invalid formats:
plaintext
@missing.start
missing@at
double@@sign.com
invalid@chars_here.com
missing@tld.
)";
EXPECT_EQ(emails(text), std::vector<std::string>({}));
}

TEST(EmailExtractionTest, MixedContent) {
const std::string text = R"(
Valid: [email protected], [email protected]
Invalid: bad@email, @wrong.com
Almost valid: almost@valid. but with space
Trash: !@#$%^&*
Valid but tricky: "[email protected]" (should extract without quotes)
)";
EXPECT_EQ(emails(text), std::vector<std::string>(
{"[email protected]", "[email protected]", "[email protected]"}));
}

TEST(EmailExtractionTest, EdgeCases) {
const std::string text = R"(
Minimal: [email protected]
Long domain: [email protected]
Special chars: [email protected]
Numbers: [email protected]
Hyphens: [email protected]
Quotes: "[email protected]"
)";
EXPECT_EQ(emails(text),
std::vector<std::string>({"[email protected]", "[email protected]",
"[email protected]", "[email protected]",
"[email protected]", "[email protected]"}));
}
3 changes: 3 additions & 0 deletions week-15/task-12-20/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_directories(include)

add_subdirectory(test)
59 changes: 59 additions & 0 deletions week-15/task-12-20/include/calculator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <cassert>
#include <sstream>
#include <stack>

inline bool is_operator(const std::string& str) {
if (str.size() != 1) {
return false;
}
const char c = str[0];
return c == '+' || c == '-' || c == '*' || c == '/';
}

inline bool may_be_number(const std::string& str) {
return (str[0] == '-' && str.size() > 1) || static_cast<bool>(std::isdigit(str[0]));
}

double calculate(const std::string& str) {
if (str.empty()) {
throw std::invalid_argument("empty string");
}
std::stack<double> stack;
std::istringstream iss(str);
std::string token;
while (iss >> token) {
assert(!token.empty());
if (may_be_number(token)) {
stack.push(std::stod(token));
} else if (is_operator(token)) {
if (stack.size() < 2) {
throw std::invalid_argument("too few arguments for operation");
}
const double b = stack.top();
stack.pop();
const double a = stack.top();
stack.pop();
switch (token[0]) {
case '+':
stack.push(a + b);
break;
case '-':
stack.push(a - b);
break;
case '*':
stack.push(a * b);
break;
case '/':
stack.push(a / b);
break;
default:
throw std::invalid_argument("unexpected operator");
}
} else {
throw std::invalid_argument("unexpected token");
}
}
return stack.top();
}
1 change: 1 addition & 0 deletions week-15/task-12-20/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp_test(test-12-20.cpp)
63 changes: 63 additions & 0 deletions week-15/task-12-20/test/test-12-20.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "calculator.hpp"
#include "gtest/gtest.h"

TEST(RPNCalculatorTest, BasicOperations) {
EXPECT_DOUBLE_EQ(calculate("3 4 +"), 7.0);
EXPECT_DOUBLE_EQ(calculate("5 2 -"), 3.0);
EXPECT_DOUBLE_EQ(calculate("2 3 *"), 6.0);
EXPECT_DOUBLE_EQ(calculate("6 2 /"), 3.0);
}

TEST(RPNCalculatorTest, FloatingPointOperations) {
EXPECT_DOUBLE_EQ(calculate("3.5 4.2 +"), 7.7);
EXPECT_DOUBLE_EQ(calculate("5.1 2.3 -"), 2.8);
EXPECT_DOUBLE_EQ(calculate("2.5 3.2 *"), 8.0);
EXPECT_DOUBLE_EQ(calculate("7.5 2.5 /"), 3.0);
}

TEST(RPNCalculatorTest, ComplexExpressions) {
EXPECT_DOUBLE_EQ(calculate("3 4 2 * +"), 11.0);
EXPECT_DOUBLE_EQ(calculate("5 1 2 + 4 * + 3 -"), 14.0);
EXPECT_DOUBLE_EQ(calculate("4 2 5 * + 1 3 - /"), -7.0);
}

TEST(RPNCalculatorTest, EdgeCases) {
EXPECT_DOUBLE_EQ(calculate("0 5 +"), 5.0);
EXPECT_DOUBLE_EQ(calculate("1 1 -"), 0.0);
EXPECT_DOUBLE_EQ(calculate("999 1 +"), 1000.0);
EXPECT_DOUBLE_EQ(calculate("-5 3 +"), -2.0);
}

TEST(RPNCalculatorTest, InvalidInput) {
EXPECT_THROW(calculate(""), std::invalid_argument);
EXPECT_THROW(calculate("3 +"), std::invalid_argument);
EXPECT_THROW(calculate("3 4 + -"), std::invalid_argument);
EXPECT_THROW(calculate("a b +"), std::invalid_argument);
}

TEST(RPNCalculatorTest, WhitespaceHandling) {
EXPECT_DOUBLE_EQ(calculate(" 3 4 + "), 7.0);
EXPECT_DOUBLE_EQ(calculate("3\n4\t+"), 7.0);
EXPECT_DOUBLE_EQ(calculate("3 4 + "), 7.0);
}

TEST(RPNCalculatorTest, MultiDigitNumbers) {
EXPECT_DOUBLE_EQ(calculate("10 20 +"), 30.0);
EXPECT_DOUBLE_EQ(calculate("100 50 -"), 50.0);
EXPECT_DOUBLE_EQ(calculate("12 34 *"), 408.0);
EXPECT_DOUBLE_EQ(calculate("100 5 /"), 20.0);
}

TEST(RPNCalculatorTest, PrecisionHandling) {
EXPECT_DOUBLE_EQ(calculate("0.1 0.2 +"), 0.3);
EXPECT_DOUBLE_EQ(calculate("1.234 2.345 +"), 3.579);
EXPECT_NEAR(calculate("1.0 3.0 /"), 0.333333, 1e-6);
EXPECT_NEAR(calculate("2.0 3.0 /"), 0.666666, 1e-6);
}

TEST(RPNCalculatorTest, MixedIntegerAndFloatingPoint) {
EXPECT_DOUBLE_EQ(calculate("3 4.5 +"), 7.5);
EXPECT_DOUBLE_EQ(calculate("5.2 2 -"), 3.2);
EXPECT_DOUBLE_EQ(calculate("2 3.5 *"), 7.0);
EXPECT_DOUBLE_EQ(calculate("6.6 2.2 /"), 3.0);
}