#include "pch.h"
#include <iostream>
#include <clocale>
#include <string>
#include <string.h>
#include <cstring>
#include <Windows.h>
#include <math.h>
#include <algorithm>
#include <iterator>
#define DEFAULT_MIN_WIDTH 5
using std::cin;
using std::cout;
using std::endl;
struct Text
{
std::string line; //хранит строку
int length; //хранит длину строки
Text* next;
Text* prev;
};
void textEntering(Text*& Head, Text*& Tail, Text*& current, int &lines_amount); //ввод текста в список
void textShowing(Text*& Head, Text*& Tail, Text*& current, int& lines_amount); //вывод текста на экран
void spacesDeleting(Text*& Head, Text*& current, int& lines_amount); //удаление пробелов в тексте
void spacesInLineDeleting(Text*& current, int start_pos = 0); //удаление пробелов в строке
void releaseMemory(Text*& Head, Text*& Tail, Text*& current); //очистка памяти
void addLine(Text*& Tail, Text* current, int& lines_amount); //добавляет строку в конец текста
void lineAligning(Text*& current, int& width); //выравнивание одной строки
void lineShifting(Text*& current, int &width); //перенос строки
int spacesCounting(std::string &line, int& paragraph_amount); //считает количество пробелов в строке
int additionalSpacesCounting(int& width, int& line_length, int &spaces_in_line_amount); //считает количество пробелов, которые надо добавить
int extraSpacesCounting(int& width, int& line_length, int& spaces_in_line_amount); //считает количество лишних пробелов, которые нельзя поровну раскидать между словами
int minWidthCounting(Text*& Head); //считает минимально возможную ширину выравнивания
int main()
{
system("color A");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
Text* Head;
Text* Tail;
Text* current;
int lines_amount; //количество строк в тексте
int width; //ширина строки
cout « "Исходный текст: \n\n";
textEntering(Head, Tail, current, lines_amount);
spacesDeleting(Head, current, lines_amount);
int minimal_width = minWidthCounting(Head); //наименьшая возможная ширина выравнивания текста
do
{
system("cls");
cout « "\nВведите ширину выравнивания (не меньше " « minimal_width «"): ";
cin » width;
if (width < minimal_width)
{
cout « "\nШирина меньше минимальной.";
system("pause");
}
} while (width < minimal_width);
current = Head;
for (int i = 1; i <= lines_amount; ++i)
{
if (current->length > width)
{
if (current->next == NULL)
addLine(Tail, current, lines_amount);
lineShifting(current, width);
}
//последнюю строчку выравнивать не надо
if(i != lines_amount)
lineAligning(current, width);
current = current->next;
}
textShowing(Head, Tail, current, lines_amount);
cout « endl;
system("pause");
releaseMemory(Head, Tail, current);
return 0;
}
void textEntering(Text*& Head, Text*& Tail, Text*& current, int& lines_amount)
{
Head = new Text;
Tail = Head;
current = Head;
lines_amount = 1;
getline(cin, current->line);
current->length = current->line.length();
current->prev = NULL;
current->next = NULL;
//ввод строк, пока на конце не окажется точка
while (current->line[current->length - 1] != '.')
{
Tail = new Text;
Tail->prev = current;
Tail->next = NULL;
current->next = Tail;
current = Tail;
lines_amount += 1;
getline(cin, current->line);
current->length = current->line.length();
}
}
void textShowing(Text*& Head, Text*& Tail, Text*& current, int& lines_amount)
{
current = Head;
system("cls");
for (int i = 1; i <= lines_amount; ++i)
{
cout « current->line « endl;
current = current->next;
}
}
void spacesDeleting(Text*& Head, Text*& current, int& lines_amount)
{
current = Head;
//Установка старотовой позиции сразу после абзаца (для первой строки)
int start_pos = 0;
while (current->line[start_pos] == ' ')
start_pos++;
spacesInLineDeleting(current, start_pos); //удаление пробелов с учётом абзаца (для первой строки)
current = current->next;
for (int i = 2; i <= lines_amount; ++i)
{
spacesInLineDeleting(current);
current =
current->next;
}
}
void spacesInLineDeleting(Text*& current, int start_pos)
{
int first_space_pos; //позиция первого пробела
int last_space_pos; //позиция последнего пробела
for (int i = start_pos; i < current->length; ++i)
{
if (current->line[i] == ' ')
{
int k = i;
first_space_pos = k;
//проход по всем "лишним пробелам", поиск позиции последнего пробела
while (current->line[k] == ' ' && k != current->length - 1)
k++;
last_space_pos = k - 1;
current->line.erase(first_space_pos + 1, last_space_pos - first_space_pos); //удаление всех пробелов кроме первого между двумя словами
current->length = current->line.length(); //перезапись длины строки
}
}
}
void lineAligning(Text*& current, int& width)
{
int spaces_in_line_amount; //количество пробелов в исходной строке
int spaces_to_add_amount; //количество доп. пробелов, которые надо добавить
int extra_spaces_amount; //количество лишних пробелов, если доп. пробелы нельзя раскидать между словами поровну
int paragraph_amount = NULL; //количество пробелов абзаца
//подсчёт количества пробелов абзаца
while (current->line[paragraph_amount] == ' ')
paragraph_amount++;
spaces_in_line_amount = spacesCounting(current->line, paragraph_amount);
spaces_to_add_amount = additionalSpacesCounting(width, current->length, spaces_in_line_amount);
extra_spaces_amount = extraSpacesCounting(width, current->length, spaces_in_line_amount);
int iterator = paragraph_amount;
int space_number = 1; //номер обрабатываемого пробела
int extra_spaces_starting_number = spaces_in_line_amount - extra_spaces_amount + 1; //номер пробела с которого нужно добавлять по одному лишнему пробелу
//если строка состоит из одного слова (нет пробелов), то добавляется пробел в конец
if (spaces_in_line_amount == NULL)
current->line += " ";
while (iterator <= width)
{
if (current->line[iterator] == ' ')
{
if (space_number == extra_spaces_starting_number)
spaces_to_add_amount++;
if (spaces_to_add_amount != NULL)
current->line.insert(iterator + 1, spaces_to_add_amount, ' '); //вставка дополнительных пробелов после основного
current->length += spaces_to_add_amount;
iterator += (spaces_to_add_amount + 1); //итератор перескакивает на следующее слово
space_number += 1;
}
else
iterator += 1;
}
}
void lineShifting(Text*& current, int& width)
{
int last_element = width - 1; //номер последнего символа в строке шириной width
std::string line_to_shift = ""; //часть строки, которую надо переносить
std::string next_line = current->next->line;
int shift; //сдвиг позиции начала отрезания строки
if (current->line[last_element] == ' ')
{
last_element--;
shift = 2;
}
else if (current->line[last_element + 1] == ' ')
{
shift = 2;
}
else
shift = 1;
line_to_shift = current->line.substr(last_element + shift);
current->line = current->line.substr(0, last_element + 1);
current->length = current->line.length();
current->next->line = line_to_shift + "" + next_line;
current->next->length = current->next->line.length();
}
void addLine(Text*& Tail, Text* current, int& lines_amount)
{
current = Tail;
Tail = new Text;
Tail->prev = current;
Tail->next = NULL;
Tail->line = "";
current->next = Tail;
current = Tail;
++lines_amount;
}
int spacesCounting(std::string& line, int& paragraph_amount)
{
int spaces_amount = NULL;
for (int i = paragraph_amount + 1; i < line.length(); ++i)
if (line[i] == ' ')
spaces_amount++;
return spaces_amount;
}
inline int additionalSpacesCounting(int& width, int& line_length, int &spaces_in_line_amount)
{
int additional_spaces; //количество дополнительных пробелов, которые нужно раскидать поровну между словами
if (spaces_in_line_amount != NULL)
additional_spaces = (width - line_length) / spaces_in_line_amount;
else
additional_spaces = width - line_length;
return additional_spaces;
}
inline int extraSpacesCounting(int& width, int& line_length, int& spaces_in_line_amount)
{
int e
xtra_spaces; //количество лишних пробелов - 0, если доп. пробелы можно раскидать поровну между словами
if (spaces_in_line_amount != NULL)
extra_spaces = (width - line_length) % spaces_in_line_amount;
else
extra_spaces = 0;
return extra_spaces;
}
int minWidthCounting(Text*& Head)
{
int min_width = NULL; //наибольшая длина слова
while (Head->line[min_width] == ' ')
min_width++;
//если нет отступа в начале строки, то возвращает минимальную возможную длину
//если отступ есть, то возвращает длину отступа + 1 символ
if (min_width == NULL)
return DEFAULT_MIN_WIDTH;
else
return min_width + 1;
}
void releaseMemory(Text*& Head, Text*& Tail, Text*& current)
{
current = Head->next;
while (current != NULL)
{
delete current->prev;
current = current->next;
}
delete Tail;
}