Скачиваний:
38
Добавлен:
10.09.2019
Размер:
13.91 Кб
Скачать
#include <iostream>
#include <cmath>
#include <stdexcept>

using std::cin;
using std::cout;
using std::endl;

// Класс «Строка» без использования функций стандартных библиотек cstring и string
class String {
 private:

    // Указатель на массив символов
    char *string_ = nullptr;
    // Размер строки
    size_t n_ = 0;

    // Функция вычисления длины строки (с учетом '\0')
    static size_t len(const char *str) {
        size_t i = 0;
        if (str) {
            ++i;
            while (*str != '\0') {
                ++str;
                ++i;
            }
        }
        return i;
    }

 public:

    // Конструкторы
    String() = default;

    explicit String(const char *s) {
        if (s != nullptr) {
            n_ = len(s);
            string_ = new char[n_];
            std::copy(s, s + n_, string_);
            string_[n_ - 1] = '\0';
        }
    }

    // Строка из массива символов. Включение: [start, end)
    explicit String(const char *start, const char *end) {
        if (start != nullptr && end != nullptr) {
            n_ = end - start + 1;
            string_ = new char[n_];
            std::copy(start, end, string_);
            string_[n_ - 1] = '\0';
        }
    }

    // Конструктор по размеру строки
    explicit String(size_t i) {
        if (i > 0) {
            n_ = i;
            string_ = new char[n_] {'\0'};
        }
    }

    // Конструктор копирования
    String(const String &arg) {
        n_ = arg.n_;
        if (n_ > 0) {
            string_ = new char[n_];
            std::copy(arg.string_, arg.string_ + n_, string_);
        }
    }

    // Оператор копирования
    String &operator=(const String &arg) {
        String temp(arg);
        swap(*this, temp);
        return *this;
    }

    // Конструктор перемещения
    String(String &&arg) noexcept {
        n_ = arg.n_, string_ = arg.string_;
        arg.n_ = 0, arg.string_ = nullptr;
    }

    // Оператор перемещения
    String &operator=(String &&arg) noexcept {
        if (this != &arg) {
            swap(*this, arg);
            delete[] arg.string_, arg.string_ = nullptr;
            arg.n_ = 0;
        }
        return *this;
    }

    // Деструктор
    virtual ~String() {
        delete[] string_;
    }

    // Оператор получения символа строки по индексу
    char &operator[](size_t idx) {
        return string_[idx];
    }

    // Длина (без учета символа '\0')
    size_t length() const {
        return ( n_ > 1 ) ? ( n_ - 1 ) : 0;
    }

    // Поиск символа ch в строке, начиная с индекса start (при неудаче возврат длины строки)
    size_t find(char ch, size_t idx) const {
        if (string_) {
            char *t = string_ + idx;
            while (*t != '\0' && *t != ch) {
                ++t;
            }
            return t - string_;
        }
        return 0;
    }

    // Поиск последнего вхождения символа ch в строке (при неудаче возврат длины строки)
    size_t findLast(char ch) const {
        if (string_) {
            char *t = string_ + n_;
            while (t != string_ && *t != ch) {
                --t;
            }
            if (*t == ch) { // Если символ был найден
                return t - string_;
            }
            return length();
        }
        return 0;
    }

    // Выделение подстроки размера count из строки, начиная с позиции idx
    String substr(size_t idx, size_t count) const noexcept(false) {
        if (idx + count < n_) { // Ex. idx = 0, count = 1, N = 2 (with '\0'), ((0 + 1) < 2)!
            return String(string_ + idx, string_ + idx + count);
        }
        throw std::invalid_argument("String. Method substr. Index + Count > N");
    }

    // Генерация новой строки с удаленными count символами, начиная с позиции idx
    String remove(size_t idx, size_t count) const noexcept(false) {
        if (idx + count < n_) {
            String result(string_, string_ + n_ - count - 1);
            std::copy(string_, string_ + idx, result.string_);
            std::copy(string_ + idx + count, string_ + n_, result.string_ + idx);
            return result;
        }
        throw std::invalid_argument("String. Method remove. Index + Count > N");
    }

    // Вставка подстроки arg в строку, начиная с позиции idx
    String insert(const char *arg, size_t idx) const noexcept(false) {
        if (idx < n_) {
            size_t arg_len = len(arg) - 1; // Не копируем символ '\0'
            String result(n_ + arg_len); // "000000"
            std::copy(string_, string_ + idx, result.string_); // "120000"
            std::copy(arg, arg + arg_len, result.string_ + idx); // "12--00"
            std::copy(string_ + idx, string_ + n_, result.string_ + idx + arg_len); // "12--56"
            return result;
        }
        throw std::invalid_argument("String. Method insert. Index > N");
    }

    // Удаление результирующих и завершающих пробелов
    String trim() const noexcept(false) {
        if (string_) {
            char *start = string_, *stop = string_ + n_ - 2; // n - 1: '\0'
            while (*start == ' ' || *start == '\t') {
                ++start;
            }
            while (*stop == ' ' || *stop == '\t') {
                --stop;
            }
            return this->substr(start - string_, stop - start + 1);
        }
        throw std::invalid_argument("String. Method trim");
    }

    // Чтение строки неопределенной длины из потока os [os must have method get()]
    static String read(std::istream &os) {
        // Начальное количество символов t = 10
        size_t i = 0, t = 10;
        char *buffer = new char[t]; // Массив размера t
        while (( buffer[i] = os.get() ) != '\n') { // Выполнять тело цикла, пока не введен конец строки
            if (++i < t) { // Если в массиве ещё есть место
                continue; // Продолжаем
            }
            // Увеличиваем количество символов
            char *new_buffer = new char[t * 2]; // Указатель на новый массив в new_buffer
            std::copy(buffer, buffer + t, new_buffer); // Копируем из старого в новый
            std::swap(buffer, new_buffer); // Меняем местами
            delete[] new_buffer; // Освобождаем старый
            t *= 2; // В два раза увеличиваем
        }
        String result(buffer, buffer + i); // Конструируем String
        delete[] buffer; // Освобождаем буфер
        return result;
    }

    // Оператор приведения к типу bool
    explicit operator bool() {
        return n_ > 1;
    }

    // Оператор сравнения 'равно'
    bool operator==(const String &arg) {
        char *s = string_;
        char *s_arg = arg.string_;
        if (s && s_arg) {
            while (*s != '\0' && *s_arg != '\0' && *s == *s_arg) {
                ++s;
                ++s_arg;
            }
            return *s == *s_arg;
        }
        return s == s_arg;
    }

    // Оператор сравнения 'не равно'
    bool operator!=(const String &arg) {
        return !( *this == arg );
    }

    // Дружественный оператор для вывода строки в выходной поток os (cout, ...)
    friend std::ostream &operator<<(std::ostream &os, const String &arg) {
        if (arg.n_ > 0) {
            os << arg.string_;
        }
        return os;
    }

    friend void swap(String &first, String &second) noexcept {
        std::swap(first.string_, second.string_);
        std::swap(first.n_, second.n_);
    }
};

int main() {
    // Создание строк
    String strA("Okay"), strB("Hello, world!");
    // Вывод строк на экран
    cout << "String A: " << strA << endl;
    cout << "String B: " << strB << endl;
    // Получение длины строки
    cout << "String A len: " << strA.length() << endl;
    cout << "String B len: " << strB.length() << endl;
    // Копирование строки при помощи конструктора
    String strC(strA);
    cout << "1. String C (String A)" << endl;
    cout << "String A: " << strA << endl;
    cout << "String C: " << strC << endl;
    // Копирование строки при помощи оператора присваивания
    strC = strB;
    cout << "2. String C = String B" << endl;
    cout << "String B: " << strB << endl;
    cout << "String C: " << strC << endl;
    // Перемещение строки при помощи конструктора
    String strD(std::move(strA));
    cout << "3. String D (move(String A))" << endl;
    cout << "String A: " << strA << endl;
    cout << "String D: " << strD << endl;
    // Перемещение строки при помощи оператора присваивания
    strD = std::move(strB);
    cout << "4. String D = move(String B)" << endl;
    cout << "String B: " << strB << endl;
    cout << "String D: " << strD << endl;
    // Поиск символа в строке, начиная с позиции start и поиск последнего вхождения подстроки в строку
    cout << "Find (o, 0) = " << strD.find('o', 0) << endl;
    cout << "Find (o, 5) = " << strD.find('o', 5) << endl;
    // [Find] Если символ не найден, то результат равен размеру строки
    cout << "Find (o, 10) = " << strD.find('o', 10) << endl;
    cout << "FindLast (o) = " << strD.findLast('o') << endl;
    cout << "Find (w, 0) = " << strD.find('w', 0) << endl;
    cout << "Find (w, 10) = " << strD.find('w', 10) << endl;
    cout << "FindLast (w) = " << strD.findLast('w') << endl;
    // [FindLast] Если символ не найден, то результат равен размеру строки
    cout << "FindLast (d) = " << strD.findLast('d') << endl;
    cout << "FindLast (k) = " << strD.findLast('k') << endl;
    // Выделение подстроки, начиная с индекса idx с длиной выделяемой подстроки count
    for (size_t i = 0; i < strD.length(); ++i) {
        cout << strD.substr(i, 1);
    }
    cout << endl;
    cout << "Substr (0, 1) = " << strD.substr(0, 1) << " (length: " << strD.substr(0, 1).length() << ')' << endl;
    cout << "Substr (2, 4) = " << strD.substr(2, 4) << " (length: " << strD.substr(2, 4).length() << ')' << endl;
    // Удаление подстроки, начиная с индекса idx с длиной удаляемой подстроки count
    cout << "Remove (0, 1) = " << strD.remove(0, 1) << " (length: " << strD.remove(0, 1).length() << ')' << endl;
    cout << "Remove (1, 3) = " << strD.remove(1, 3) << " (length: " << strD.remove(1, 3).length() << ')' << endl;
    cout << "Remove (5, 4) = " << strD.remove(5, 4) << " (length: " << strD.remove(5, 4).length() << ')' << endl;
    // Вставка подстроки s в строку strD в позицию index
    cout << "Insert (Okay, 0) = " << strD.insert("Okay", 0) << " (length: " << strD.insert("Okay", 0).length() << ')'
         << endl;
    cout << "Insert (Okay, 1) = " << strD.insert("Okay", 1) << " (length: " << strD.insert("Okay", 1).length() << ')'
         << endl;
    cout << "Insert (Okay, 13) = " << strD.insert("Okay", 13) << " (length: " << strD.insert("Okay", 13).length() << ')'
         << endl;
    // Удаление из строки ведущих и завершающих пробелов и табуляций
    String strF("  spaces    "), strG("\t 1  length        \t     \t");
    cout << "Trim: " << strF.trim() << " (length: " << strF.trim().length() << ')' << endl;
    cout << "Trim: " << strG.trim() << " (length: " << strG.trim().length() << ')' << endl;
    // Чтение строки неопределенной длины до перевода строки и её сохранение в readString
    String readString(String::read(cin));
    cout << "New String: " << readString << " (length: " << readString.length() << ')' << endl;
    cout << "New String == New String: " << ( readString == String(readString) ) << endl;
    cout << "New String != New String: " << ( readString != String(readString) ) << endl;
    if (readString.length() > 0) {
        String temp(readString);
        temp[0] = '5';
        cout << "New String: " << readString << " (length: " << readString.length() << ')' << endl;
        cout << "Temp: " << temp << " (length: " << temp.length() << ')' << endl;
        cout << "New String == Temp: " << ( readString == temp ) << endl;
        cout << "New String != Temp: " << ( readString != temp ) << endl;
    }
}