Перенос слова по правилам русского языка

Мне нужно перенести предложение на новую строку по правилам русского языка. В одной строчке не должно быть больше "n" символов, если лимит привышается то перенести слово на следующую строку.

Моя попытка кода:

"После использования этой команды вы получите информацию и статистику о себе".replace(/(.{42})/g,"$1\-\n")

Регс переносит слово если строка превышает лимит в 42 символа. Однако перенос осуществляется не по правилам.


Ответы (2 шт):

Автор решения: DronDron

Если под правилами понимать то что нельзя переносить/оставлять одну букву, то попробуйте эту функцию:

function createLineBreaks(text) {
    return text.split(/(?=(?<!.{42,})(?:(?<=[^ ])[^ ](?=[^ ]{2})| )(?!.*(?<!.{42,})(?:(?<=[^ ])[^ ](?=[^ ]{2})| )))/).join("\n");
}

UPD:
Да, немножко накосячил (простите :) ). Не знал как split в js'се работает... Вот обновлённая версия:

function createLineBreaks(text) {
    text = new Array(text);
    let lastIndex = 0;
    while (text[lastIndex].length > 42) {
        const temp = text[lastIndex].split(/(?=(?<!.{42,})(?:(?<=[a-zA-Zа-яА-Я]{2})[a-zA-Zа-яА-Я](?=[a-zA-Zа-яА-Я])| )(?!.*(?<!.{42,})(?:(?<=[a-zA-Zа-яА-Я]{2})[a-zA-Zа-яА-Я](?=[a-zA-Zа-яА-Я])| ))) ?/);
        text[lastIndex] = temp[0];
        text[lastIndex + 1] = temp[1];
        lastIndex++;
    }
    return text.join("\n");
}

функция подлиннее, но эти баги ушли.

→ Ссылка
Автор решения: Laukhin Andrey

Непосредственно регуляркой эту задачу не решить. Как отметили выше, чтобы строго следовать правилам, нужно учитывать морфемное строение слова.

Но, взяв в подмогу регулярное выражение, всё же можно добиться неплохого результата.
Для начала несколько замечаний:

  1. Правила переноса не являются строгими, а носят скорее рекомендательный характер.
  2. Базовое правило переноса - по слогам.
  3. Правила разделения на слоги отличаются в школьной программе и в вузах. Совокупно, правила переноса ближе к разделению на слоги по школьной программе.
  4. Чаще переносится часть слова с согласной в начале.
  5. Возможен перенос слова целиком (без разделения), тогда тире в конце строки не требуется.
  6. Одну букву не переносим.

Учитывая выше сказанное, я составил регулярное выражение:

[бвгджзйклмнпрстфхцчшщ]+[аеёиоуыэюя][бвгджзйклмнпрстфхцчшщ](?=[бвгджзйклмнпрстфхцчшщьъ ])[ьъй]?|[бвгджзйклмнпрстфхцчшщ]+[аеёиоуыэюя][й]?|[аеёиоуыэюя][бвгджзйклмнпрстфхцчшщ](?=[бвгджзйклмнпрстфхцчшщьъ ])[ъь]?|[аеёиоуыэюя](?=[а-я]{2})|(?<= +)[^\s]+(?= +|$)

Проверить онлайн

Не обращайте внимания на невыделенные окончания у некоторых слов. Меня интересуют индексы слогов, т.е. где они начинаются. Также добавляются союзы и всё, что не соответствует основным правилам РВ.

Далее, алгоритм простой, просматриваем индексы, если вышли за лимит, делаем перенос на предыдущем индексе. Однобуквенные слоги в начале слова игнорируем:

const regex = /[бвгджзйклмнпрстфхцчшщ]+[аеёиоуыэюя][бвгджзйклмнпрстфхцчшщ](?=[бвгджзйклмнпрстфхцчшщьъ ])[ьъй]?|[бвгджзйклмнпрстфхцчшщ]+[аеёиоуыэюя][й]?|[аеёиоуыэюя][бвгджзйклмнпрстфхцчшщ](?=[бвгджзйклмнпрстфхцчшщьъ ])[ъь]?|[аеёиоуыэюя](?=[а-я]{2})|(?<= +)[^\s]+(?= +|$)/gmi;

function wordWrap(text, limit) {
  let out = '', offset = 0, prev = 0, pass = false;
  let matches = text.matchAll(regex);

  for (const m of matches) {
    if (m.index - offset > limit) {
      let hyphen = text[prev - 1] == ' ' ? '' : '-';
      out += text.substring(offset, prev) + hyphen + '\n';
      offset = prev;
    }

    if (!pass) prev = m.index;
    pass = m[0].length < 2;
  }

  out += text.substring(offset);
  return out;
}

input.oninput = text.oninput = () => dtext.innerText = wordWrap(text.value, input.value);
input.oninput();
<input id="text" type="text" style="width: 100%" value="Правила переноса слов рекомендуют переносить слова с одной строки на другую по слогам с учетом морфемного строения. В письменной речи слова переносятся с одной строки на другую в соответствии с определенными правилами переноса.">
<hr>
<input id="input" type="number" min="3" max="100" value="42">
<pre id="dtext" style=""></pre>

На мой взгляд, вполне удовлетворительный результат. Можно еще похимичить с регуляркой, например, добавить приставки.

→ Ссылка