diff --git a/README.md b/README.md index 7b0d455..b6760a9 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ d-examples ├── common Общего назначения │ ├── isexists Проверяет наличие исполняемого файла в директориях,указанных в переменной окружения PATH +│ └── splittext Форматирует массив строк, разбивая их на строки указанной длины ├── ncurses Использование библиотеки ncurses │ ├── menu Интерактивное консольное меню │ └── password Консольное окно для ввода пароля diff --git a/source/app.d b/source/app.d index fdb3759..7f8330b 100644 --- a/source/app.d +++ b/source/app.d @@ -10,6 +10,8 @@ int main(string[] args) .add(new Command("common", "Общего назначения") .add(new Command("isexists", "Проверяет наличие исполняемого файла в директориях,указанных в переменной окружения PATH")) + .add(new Command("splittext", + "Форматирует массив строк, разбивая их на строки указанной длины")) ) .add(new Command("ncurses", "Использование библиотеки ncurses") .add(new Command("menu", "Интерактивное консольное меню")) @@ -23,6 +25,7 @@ int main(string[] args) argumets .on("common", (common) { common + .on("splittext", (splittext) { formatLines(); }) .on("isexists", (isexists) { isExists(); }); }) .on("ncurses", (ncurses) { ncurses diff --git a/source/examples/common/README.md b/source/examples/common/README.md index cabdc5a..bd1b1dc 100644 --- a/source/examples/common/README.md +++ b/source/examples/common/README.md @@ -1,5 +1,9 @@ # Общего назначения +## splittext + +Функция `splitText` форматирует массив строк, разбивая их на строки длиной не более `length` (по умолчанию 50 символов). Преобразует входные строки в `dstring` (UTF-32), разбивает их на слова и обрабатывает каждое слово. Если слово длиннее `length`, оно разбивается на части. Сохраняет один пробел в начале строки, если она начинается с пробельного символа, и добавляет пробелы между словами. Пустые строки добавляются в результат без изменений. Возвращает массив отформатированных строк `dstring[]`. Использует модули `std.conv`, `std.string`, `std.uni`. + ## isexists Функция `isExecutableExists` проверяет наличие исполняемого файла `appName` в директориях, указанных в переменной окружения `PATH`. Разбивает `PATH` на директории, формирует полный путь к файлу и проверяет его существование и тип (файл). Возвращает `true`, если файл найден, иначе `false`. Использует модули `std.process`, `std.file`, `std.path`, `std.array`. diff --git a/source/examples/common/package.d b/source/examples/common/package.d index 762aa45..68466fa 100644 --- a/source/examples/common/package.d +++ b/source/examples/common/package.d @@ -1,3 +1,4 @@ module examples.common; public import examples.common.isexists; +public import examples.common.splittext; diff --git a/source/examples/common/splittext.d b/source/examples/common/splittext.d new file mode 100644 index 0000000..fc23e82 --- /dev/null +++ b/source/examples/common/splittext.d @@ -0,0 +1,93 @@ +module examples.common.splittext; + +import std.conv : to; +import std.uni : isWhite; +import std.array : split; +import std.stdio : writeln; + +private dstring[] splitText(string[] text, size_t length = 50) { + // Инициализация массива для хранения результата + dstring[] result; + + // Перебор каждой строки входного текста + foreach (line; text) { + // Преобразование строки в dstring для поддержки Unicode + dstring lineD = line.to!dstring; + + // Разделение строки на слова по пробелам + dstring[] words = lineD.split(); + + // Если строка пустая или содержит только пробелы, добавляем пустую строку + if (!words.length) { + result ~= ""; + continue; + } + + // Инициализация текущей строки для сборки результата + dstring currentLine; + + // Проверка, начинается ли строка с пробела, и добавление пробела к первому слову + if (isWhite(lineD[0])) { + words[0] = ' ' ~ words[0]; + } + + // Перебор всех слов в строке + foreach (idx, word; words) { + // Если слово длиннее максимальной длины строки + if (word.length > length) { + // Начальная позиция для разбиения слова + size_t start = 0; + // Разбиение длинного слова на части + while (start < word.length) { + // Вычисление конца текущего фрагмента слова + size_t end = start + length; + if (end > word.length) end = word.length; + // Если добавление фрагмента превысит длину строки + if (currentLine.length + (end - start) > length) { + // Сохраняем текущую строку и начинаем новую с фрагмента слова + result ~= currentLine; + currentLine = word[start .. end]; + } else { + // Добавляем пробел, если текущая строка не пуста + if (currentLine.length) { + currentLine ~= " "; + } + // Добавляем фрагмент слова к текущей строке + currentLine ~= word[start .. end]; + } + // Сдвигаем начальную позицию для следующего фрагмента + start += length; + } + } else { + // Если добавление слова (и пробела, если нужно) превысит длину строки + if (currentLine.length + word.length + (currentLine.length ? 1 : 0) > length) { + // Сохраняем текущую строку и начинаем новую со слова + result ~= currentLine; + currentLine = word; + } else { + // Добавляем пробел, если текущая строка не пуста + if (currentLine.length) { + currentLine ~= ' '; + } + // Добавляем слово к текущей строке + currentLine ~= word; + } + } + } + + // Если текущая строка не пуста, добавляем её в результат + if (currentLine.length) { + result ~= currentLine; + } + } + + // Возвращаем массив строк с учётом ограничения длины + return result; +} + +void formatLines() { + auto lines = [" Hello world this is a very long line", " Another line"]; + foreach (line; splitText(lines, 10)) { + writeln(line); + } +} diff --git a/source/examples/version_.d b/source/examples/version_.d index c643e35..373c0e0 100644 --- a/source/examples/version_.d +++ b/source/examples/version_.d @@ -1,3 +1,3 @@ module examples.version_; -enum examplesVersion = "0.3.0"; +enum examplesVersion = "0.4.0";