Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // AlexKursach.cpp: определяет точку входа для консольного приложения.
- //
- #include "stdafx.h"
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <fstream>
- #include <conio.h>
- using namespace std;
- //класс, отвечающий за хранение текста и функции (методы) для оперирования им
- class CText {
- private:
- string text; //наш текст
- string delimeters; //строка разделителей
- int numOfStrings = 0; //кол-во строк в тексте
- public:
- void setDelimeters(string inDelimeters) { //задаем разделители
- delimeters = inDelimeters;
- }
- string getDelimeters() { //возвращаем строку разделителей
- return delimeters;
- }
- void setText(string inText) { //задать текст
- text = inText;
- }
- string getText() { //возвращает наш текст
- return text;
- }
- void setNumOfStrings(int inNum) { //задать количество строк в тексте
- numOfStrings = inNum;
- }
- int getNumOfStrings() { //вернуть количество строк в тексте
- return numOfStrings;
- }
- void printText() { //вывести текст на экран
- cout << "Ваш текст: " << endl;
- for (int i = 0; i < text.length(); i++) { //идем по строке, которая хранит текст
- if (text[i] == '/n') { //если встретили перенос строки в тексте, то переходим на новую строчку
- cout << endl;
- }
- else { //иначе просто выводим символ из нашей строки текста
- cout << text[i];
- }
- }
- }
- };
- //класс, отвечающий за ввод-вывод текста
- class InOut {
- private:
- string delimeters = ""; //строка разделителей
- int numOfStrings = 0; //количество строк в тексте
- public:
- //функция, которая считывает разделители с экрана. Ничего не возвращает
- //входной параметр - объект типа CText(хранилище текста), передается по ссылке, т.к. нам нужно изменять его поля
- void readDelimeters(CText &inText) { //считать разделители с экрана
- string temp; //временная строка, из которой мы достанем все уникальные символы
- cout << "Введите в строчку не более 5 разделителей: ";
- getline(cin, temp); //считываем временную строку
- //оставляем в строке разделителей только уникальные символы
- for (int i = 0; i < temp.length(); i++) { //идем по временной строке
- bool b = false; //переменная, которая указывает на то, есть ли буква из временной строке в строке разделителей
- for (int j = 0; j < delimeters.length(); j++) {//идем по строке разделителей
- if (temp[i] == delimeters[j]) { //если буква из временной строки уже есть в строке разделителей, то b = true
- b = true;
- }
- }
- if (!b) { //если b = false, т.е. буквы из временной строки не было в строке разделителей, и добавляем эту букву в строку разделителей
- delimeters += temp[i];
- }
- }
- if (delimeters.length() == 0) { //если пользователь ничего не ввел, то за разделитель считаем пробел
- cout << endl;
- cout << "Вы ввели 0 разделителей, по умолчанию будет использоваться пробел!" << endl;
- cout << endl;
- delimeters = " "; //присваиваем пробел к нашей строке разделителей
- }
- else
- if (delimeters.length() > 5) { //если пользователь ввел больше 5-ти разделителей, т.е. строка длинее пяти символов, то сохраняем только первые пять
- cout << endl;
- cout << "Вы ввели более пяти разделителей, сохранены будут только 5!" << endl;
- cout << endl;
- delimeters = delimeters.substr(0, 5); //присваиваем строке разделителей первые пять введенных символов с помощью метода substr, где 0 - это позиция, с которой берется подстрока, а 5 - кол-во символов, которое нужно взять
- }
- else { //если пользователь ввел 1-5 разделителей, то просто сохраняем их
- cout << endl;
- cout << "Разделители успешно сохранены!" << endl;
- cout << endl;
- }
- inText.setDelimeters(delimeters); //у объекта, который мы передали через параметр, с помощью метода setDelimeters задаем разделители delimeters
- }
- //функция, которая считывает текст из файла. Возвращает true - если файл открыт, false - если открыть не получилось
- //входной параметр - объект типа CText(хранилище текста), передается по ссылке, т.к. нам нужно изменять его поля
- bool readFromFile(CText &text) {
- ifstream f; //создаем переменную для считывания данных из файла
- bool wasOpen = false; //переменная, отвечающая за то был ли открыт файл
- string str; //вспомогательная строка для считывания
- string subText; //вспом. строка, для хранения текста
- string name; //строка для хранения имени файла
- while (!wasOpen) { //пока wasOpen - false, цикл продолжается
- cout << "Введите название файла для считывания" << endl;
- cin >> name; //вводим имя файла
- f.open("C:\\Alex\\kursach\\" + name + ".txt", ios::in); //открываем файл с именем name
- wasOpen = f.is_open(); //wasOpen = true, если файл открылся
- if (!wasOpen) { //если wasOpen - false, то ты выводим след. строку на экран
- cout << "Файл не найден!" << endl;
- }
- else { //если wasOpen - true, то выводим след. строку
- cout << "Файл успешно открыт" << endl;
- }
- }
- //цикл, который выполняется, пока из файла f считывается строка в переменную str, с помощью функции getline
- while (getline(f, str)) {
- if (isCorrect(str)) { //если разделители в начале и конце совпали
- // и они не пустые, то считывание с файла заканчивается
- int key; //переменная для хранения кода нажатой клавиши
- cout << "Считана строка: " << str << endl;
- cout << "-------------------------------------------------------------" << endl;
- cout << "Найдена строка с одинаковыми разделителями в начале и в конце" << endl;
- cout << " Считывание из файла окончено! " << endl;
- cout << "-------------------------------------------------------------" << endl;
- subText += str + '\n'; //добавляем к строке, хранящей текст текущую строки. Также добавляем символ переноса строки - '\n', чтобы каждая строка была с новой строчки
- numOfStrings++; //увеличиваем кол-во строк в тексте
- cout << "Нажмите 1 для ввода двух строк с клавиатуры, или ЛЮБУЮ клавишу для продолжения" << endl;
- key = _getch(); //записываем в key код нажатой клавиши
- if (key == 49) { //если была нажата клавиша '1', то выполняем считывание с клавиатуры
- subText += readFromKeyboard(); //к строке, хранящей текст, добавляем результат функции считывания с клавиатуры (т.к. она возвращает строку, которая содержит текст, введенный с клавиатуры)
- }
- break; //выход из общего цикла считывания, т.к. по условию считывание должно быть прекращено
- }
- else { //если разделители с начала и конца не совпали, то просто продолжаем цикл
- cout << "Считана строка: " << str << endl; //выводим этот текст и саму строку для наглядности
- numOfStrings++; //увеличиваем кол-во строк в тексте
- }
- subText += str + '\n'; //считанную строка с файла добавляем к строке, хранящей текст. Добавляем символ переноса строки '\n'.
- }
- text.setNumOfStrings(numOfStrings); //у объекта хранилища текста вызываем метод для задания кол-ва строк в тексте
- text.setText(subText); //у него же с помощью метода задаем текст, который мы считали из файла и с клавиатуры
- f.close(); //закрываем файл f
- return wasOpen; //возвращаем то был ли открыт файл
- }
- //функция для проверки строки на одинаковые последовательности разделителей в начале и конце
- //возвращает true - если в начале и конце строки одинаковые последовательности разделителей
- // false - если нет
- //параметр s - строка, которую нужно проверить
- bool isCorrect(string s) {
- string firstDelimeters = ""; //строка для хранения разделителей с начала строки
- string lastDelimeters = ""; //строка для хранения разделителей с конца строки
- string temp = ""; //вспомогательная строка для переворота строки
- for (int i = 0; i < s.length(); i++) { //идем по нашей строке
- if (isDelimeter(s[i])) { //если встретили разделитель, то накапливаем разделители в переменную
- firstDelimeters += s[i];
- }
- else {
- break; //если встретили не разделитель, то либо в начале строки идет сразу слово, либо последовательность разделителей кончилась. Выходим из цикла
- }
- }
- if (firstDelimeters == "") { //если мы не встретили разделители в начале строки, то возвращаем false, т.к. пустые последовательности разделителей не подходят
- return false;
- }
- for (int i = s.length() - 1; i >= 0; i--) { //переворачиваем нашу строку
- temp += s[i];
- }
- for (int i = 0; i < temp.length(); i++) { //идем по нашей строке
- if (isDelimeter(temp[i])) {//если встретили разделитель, то накапливаем разделители в переменную
- lastDelimeters += temp[i];
- }
- else {
- break; //если встретили не разделитель, то либо в начале строки идет сразу слово, либо последовательность разделителей кончилась. Выходим из цикла
- }
- }
- if (lastDelimeters == "") { //если мы не встретили разделители в начале строки, то возвращаем false, т.к. пустые последовательности разделителей не подходят
- return false;
- }
- temp = ""; //обнуляем вспомогательную строку
- for (int i = lastDelimeters.length() - 1; i >= 0; i--) { //переворачиваем строку конечных разделителей, т.к. мы получили их в обратном порядке
- temp += lastDelimeters[i];
- }
- lastDelimeters = temp; //присваиваем конечные разделители
- if (lastDelimeters == firstDelimeters) { //если последовательности совпадают, то возвращаем тру
- return true;
- }
- else {
- return false; //иначе false
- }
- }
- //функция, которая считывает две строки с клавиатуры
- //возвращает строку, содержащую две строки, разделенные символов переноса строки '\n'
- string readFromKeyboard() {
- cin.ignore(std::numeric_limits<size_t>::max(), '\n'); //эта строка нужна для игнорирования символа переноса строки, брал из гугла, без нее не работает
- string result = ""; //результирующая строка, которую вернет функция
- string str; //вспомогательная строка
- cout << "Идет считывание с клавиатуры!" << endl;
- for (int i = 0; i < 2; i++) { //цикл, проводящий 2 итерации (задано по условию)
- cout << "Введите " << i + 1 << "-ую строку: "; //выводим доп. информацию для наглядности и удобства
- getline(cin, str); //с помощью getline считываем строку с клавиатуры в переменную str
- numOfStrings++; //увеличиваем кол-во строк
- result += str + '\n'; //к результирующей строке добавляем считанную и после нее символ переноса строки
- }
- cout << "Считывание с клавиатуры окончено!" << endl;
- return result; //функция возвращает результирующую строку
- }
- //функция, которая записывает текст в файл
- //параметр - объект хранилища текста
- //возвращает true - при удачном сохранении, false - при неудачном
- bool writeInFile(CText inText) { //метод, отвечающий за запись нашего текста из хранилища(inText) в файл
- bool wasOpen = false; //
- ofstream f; //переменная f, для записи текста в файл
- string name; //имя файла
- cout << "Введите имя файла, в котором нужно сохранить текст: ";
- cin >> name;
- while (!fileCheck(name)) { //выполняем цикл до тех пор, пока существует файл с именем, которое вводит пользователь
- cout << endl;
- cout << "Такой файл уже существует" << endl;
- cout << "Нажмите 1, чтобы перезаписать его или любую клавишу для создания нового файла. . ." << endl;
- int key = _getch(); //храним код нажатой клавиши
- if (key == 49) { //если нажата 1, то просто перезаписываем файл и выходим из цикла
- f.open("C:\\Alex\\kursach\\" + name + ".txt", ios::out);
- break;
- }
- else {//иначе просим пользователя ввести новое имя файла
- cout << "Введите имя файла, в котором нужно сохранить текст: ";
- cin >> name;
- if (fileCheck(name)) { //если файла с таким именем нет, то он создается
- f.open("C:\\Alex\\kursach\\" + name + ".txt", ios::out);
- break; //выходим из цикла
- }
- }
- }
- wasOpen = f.is_open(); //wasOpen = true, если файл открылся, иначе false
- f << inText.getText(); //записываем текст из хранилища в файл
- f.close(); //закрываем файл f
- if (wasOpen == true) { //если wasOpen - true
- cout << endl;
- cout << "Ваш текст успешно записан в файл " + name + ".txt" << endl;
- cout << endl;
- }
- else { //если wasOpen - false
- cout << endl;
- cout << "Ошибка при записи текста в файл" << endl;
- cout << endl;
- }
- return wasOpen; //возвращаем переменную wasOpen
- }
- bool fileCheck(string name) {
- ifstream check;
- check.open("C:\\Alex\\kursach\\" + name + ".txt", ios::in);
- if (check.is_open()) {
- check.close();
- return false;
- }
- else {
- check.close();
- return true;
- }
- }
- //функция, которая проверяет входящий символ на разделитель
- //параметр - символ c, который нужно проверить
- //возвращает true - если c - разделитель
- // false - c - не разделитель
- bool isDelimeter(char c) {
- for (int i = 0; i < delimeters.length(); i++) { //идем в цикле по строке разделителй
- if (c == delimeters[i]) { //если символ c равен символу из строки разделителей, то он разделитель
- return true; //функция прекращает работу, возвращает true
- }
- }
- return false; //если cимвол c не совпал ни с одним символом из строки разделителей, то он не разделителей.
- //функция прекращает работу, возвращает false
- }
- };
- //класс для редактирования текста
- class TextEditor {
- private:
- string delimeters = ""; //строка разделителей
- public:
- //функция, отвечающая за редактирования текста
- //параметр - объект хранилища текста
- void textEdit(CText &text) {
- delimeters = text.getDelimeters(); //строке разделителей приравниваем разделители объекта хранилища текста, с помощью метода getDelimeters()
- int lineCounter = 1; //переменная для хранения номера строки. Изначало равна 1. т.к. изначально мы находимся на первой строке
- int charCounter = 0; //переменная для хранения номера символа
- string subText = text.getText(); //строка для хранения текста. приравниваем текст из хранилища с помощью метода getText
- string changedText = ""; //строка для хранения измененного текста и последующего его сохранения в объект хранилища
- string str; //вспомонательная строка
- string userWord = ""; //строка для хранения слова, на которое нужно заменять первое слово в необрезанных строках
- int maxStrLength = 0; //максимальная длина строки
- int userCutLength = 0; //длина строки до которой нужно обрезать строки, выходящие за максимальную длину
- cout << "Введите максимальную длину строки: ";
- cin >> maxStrLength;
- cout << "Введите длину до которой нужно обрезать строки, выходящие за максимульную длину: ";
- cin >> userCutLength;
- cout << "Введите слово для замены, если строка не будет обрезана: ";
- cin >> userWord;
- //цикл для прохода по тексту
- //выполняется до тех пор пока lineCounter не будет равна номеру последней строки
- while (lineCounter <= text.getNumOfStrings()) {
- while (subText[charCounter] != '\n') { //цикл для накопления строки, выполняется до тех пор пока мы не встретим символ переноса строки. т.е. конец строчки
- str += subText[charCounter]; //к вспом. строке добавляем символ из строки с текстом
- charCounter++; //накапливаем переменную с кол-вом символов в строке
- }
- if (isOddBigger(subText, text.getNumOfStrings())) { //если кол-во слов в нечетных строках больше чем в четных
- cout << "Имеет длину: " << str.length() << endl;
- if (str.length() > maxStrLength) { //проверяем длину строки
- str = str.substr(0, userCutLength); //если она больше максимальной, то обрезаем
- cout << "Выходит за границу максимальной длины. Обрезана до " << userCutLength << "-ти символов" << endl;
- }
- else {//если она меньше максимальной, то заменяем в ней первое слово
- str = wordExchange(str, userWord);
- cout << "В ней заменено первое слово" << endl;
- }
- }
- else { //если кол-во слов в четных строках больше
- cout << "Строка: " << str << endl; //выводим инфу для наглядности
- str = wordExchange(str, userWord);
- cout << "В ней заменено первое слово" << endl;
- }
- changedText += str + '\n'; //в переменную для хранения измененного текста добавляем строку, по которой мы шли и добавляем символ переноса строки
- str = ""; //обнуляем вспом. строку для чтения следующей
- lineCounter++; //увеличиваем номер строки на 1
- charCounter++; //увеличиваем номер символа на 1
- }
- text.setText(changedText); //с помощью метода setText задаем новый текст - changedText
- }
- //функция, которая проверяет входящий символ на разделитель
- //параметр - символ c, который нужно проверить
- //возвращает true - если c - разделитель
- // false - c - не разделитель
- bool isDelimeter(char c) {
- for (int i = 0; i < delimeters.length(); i++) { //идем в цикле по строке разделителй
- if (c == delimeters[i]) { //если символ c равен символу из строки разделителей, то он разделитель
- return true; //функция прекращает работу, возвращает true
- }
- }
- return false; //если cимвол c не совпал ни с одним символом из строки разделителей, то он не разделителей.
- //функция прекращает работу, возвращает false
- }
- //функция, которая проверяет на равенство кол-во слов в четных и нечетных строках
- //параметры: text - строка, хранящая текст
- // numOfStrings - кол-во строк в тексте
- //возвращает true - если кол-во слов в нечетных строках больше
- // false - в других случаях
- bool isOddBigger(string text, int numOfStrings) {
- int oddWordCounter = 0; //счетчик слов в нечетных строках
- int notOddWordCounter = 0; //счетчик слов в четных строках
- int charCounter = 0; //вспомогательный счетчик символов для продвижения по тексту
- string str = ""; //вспомогательная строка, для хранения отдельной строки из текста
- int lineCounter = 1; //счетчик номера строки
- while (lineCounter <= numOfStrings) { //идем по тексту, пока не дойдем до последней сроки
- while (text[charCounter] != '\n') { //цикл для накопления строки, выполняется до тех пор пока мы не встретим символ переноса строки. т.е. конец строчки
- str += text[charCounter]; //к вспом. строке добавляем символ из строки с текстом
- charCounter++; //накапливаем переменную с кол-вом символов в строке
- }
- bool wordIsFound = false; //переменная, говорящая о том, встречено ли слово в строке
- for (int i = 0; i < str.length(); i++) {//идем по строке
- if (!isDelimeter(str[i])) {//если встречаем неразделитель, то либо мы встретили слово, либо еще движемся по слову. Для того, чтобы это понять
- if (!wordIsFound) { //смотрим переменную wordIsFound
- if (lineCounter % 2 != 0) { //если строка нечетная, то накапливаем нужный счетчик
- oddWordCounter++;
- }
- else {//иначе накапливаем другой счетчик
- notOddWordCounter++;
- }
- wordIsFound = true; //переключаем переменную wordIsFound
- }
- }
- else { //иначе переключаем wordIsFound
- wordIsFound = false;
- }
- }
- str = ""; //обнуляем вспом. строку для чтения следующей
- lineCounter++; //увеличиваем номер строки на 1
- charCounter++; //увеличиваем номер символа на 1
- }
- if (oddWordCounter > notOddWordCounter) { //если кол-во слов в нечетных строках больше, то возвращаем true
- return true;
- }
- return false; //иначе false
- }
- //функция для того, чтобы поменять первое слово в строке
- //параметры: str - строка
- // exchangeWord - слово, на которое нужно поменять
- //возвращаем измененную строку
- string wordExchange(string str, string exchangeWord) {
- bool wordIsFound = false; //вспом. переменная
- string result = ""; //результирующая строка, которую мы вернем
- for (int i = 0; i < str.length(); i++) { //идем по строке
- if (!isDelimeter(str[i])) { //если встретили неразделитель, то мы встретили слово, либо еще идем по слову
- if (wordIsFound) {//если слово найдено, то накапливаем строку в result
- result += str[i];
- }
- else { //иначе переключаем wordIsFound
- wordIsFound = true;
- while (!isDelimeter(str[i]) && i < str.length()) { //цикл, в котором мы проскочим первое слово, и не добавим его в result
- i++; //просто переходим к след. символу
- }
- result += exchangeWord; //добавляем в result нужное слово
- if (str[i] != '\n' && i < str.length()) { //условие, для того, чтобы добавить разделитель после слова
- result += str[i];
- }
- }
- }
- else { //иначе просто накапливаем result
- result += str[i];
- }
- }
- return result; //возвращаем результат
- }
- };
- int main()
- {
- setlocale(0, "");
- CText text; //создаем объекта хранилища текста
- InOut io; //создаем объект ввода-вывода
- TextEditor te; //создаем объект редактирования
- io.readDelimeters(text); //считываем разделители, сохраняем в объект хранилища
- io.readFromFile(text); //считываем текст из файла и клавы, сохраняем в объект хранилища
- te.textEdit(text); //редактируем текст из объекта хранилища, сохраняем в объект хранилища
- io.writeInFile(text); //записываем текст из объекта хринилища в файл
- text.printText(); //выводим текст из объекта хранилища на экран
- system("pause");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement