Переместить последовательность символов на следующую строку в зависимости от положения этой строки в абзаце

Вот пример текста:

  Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do a
eiusmod tempor incididunt ut labore et dolore magna aliqua. Do b c
quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
---minim a b veniam, quis nostrud exercitation ullamco laboris d.
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do a
eiusmod tempor incididunt ut labore et dolore magna aliqua. Do b c
quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
---minim a b veniam, quis nostrud exercitation ullamco laboris d.

Мне нужно обработать этот текст с помощью Awk или, возможно, Perl, чтобы

  • Правило 1: Каждое однобуквенное слово, если оно оказалось в конце строки и эта строка не является последней строкой абзаца, переносится на следующую строку.

  • Правило 2: В противном случае оно перемещается на следующую строку вместе с ближайшим словом, состоящим не менее чем из двух букв.

  • Правило 3: Три дефиса, если они оказались в начале строки и эта строка не является первой строкой абзаца, в Правиле 2 рассматриваются так же, как однобуквенные слова.

То есть текст выше следует переформатировать следующим образом:

  Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do
a eiusmod tempor incididunt ut labore et dolore magna aliqua. Do
b c quis autem vel eum iure reprehenderit qui in ea voluptate velit
esse---minim a b veniam, quis nostrud exercitation ullamco
laboris d.
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do
a eiusmod tempor incididunt ut labore et dolore magna aliqua. Do
b c quis autem vel eum iure reprehenderit qui in ea voluptate velit
esse---minim a b veniam, quis nostrud exercitation ullamco
laboris d.

Я понимаю, что, наверное, никто не станет тратить время на то, чтобы написать за меня весь сценарий, но мне нужно хотя бы иметь какие-то точки входа, чтобы начать работу. Возможно, решение будет работоспособным на 50 или 25 %.

Чтобы облегчить задачу, можно предположить, что абзацы разделены пустой строкой вместо отступа первой строки:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do a
eiusmod tempor incididunt ut labore et dolore magna aliqua. Do b c
quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
---minim a b veniam, quis nostrud exercitation ullamco laboris d.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do a
eiusmod tempor incididunt ut labore et dolore magna aliqua. Do b c
quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
---minim a b veniam, quis nostrud exercitation ullamco laboris d.

почему do a не перешёл на следующую строку, ведь do содержит как минимум 2 буквы? почему ты b c перешел на следующую строку, ведь в b нет хотя бы 2 букв?

markp-fuso 26.08.2024 00:04

для правила 2, пожалуйста, уточните, что вы подразумеваете под ближайшим словом... перед одной буквой? после единственной буквы? что-то еще? также рассмотрите возможность обновления вопроса, чтобы определить абзац для первого набора данных... я предполагаю, что это что-то вроде starts with an indent (пробелы или табуляция) и ends prior to next indented line (или конец ввода)

markp-fuso 26.08.2024 00:04

пожалуйста, обновите вопрос, указав ваши последние попытки кодирования и (неправильные) результаты, полученные указанным кодом.

markp-fuso 26.08.2024 00:08

Спасибо всем, сегодня, когда приду домой, попробую предложенные решения. Не знаю, почему за вопрос проголосовали шесть раз. Были времена, когда я регулярно отвечал на вопросы по HTML/CSS и голосовал только против людей, которые публиковали свои вопросы, даже не пытаясь использовать заглавные буквы и правильную пунктуацию.

nick 26.08.2024 11:56

Обычно вопросы таких невежественных людей понижались до -1 или -2, иногда -3, но никогда ниже этого значения. Не уверен, что заслуживаю большего. Проблема с отрицательными голосами в том, что аккаунт могут заблокировать, и всё. Мои учетные записи были заблокированы дважды в этом году и ни разу за предыдущие 15 лет использования Stack Overflow. Здесь действительно что-то изменилось...

nick 26.08.2024 11:56

@nick Я бы сказал, что люди из тега Perl обижаются на людей, которые хотят бесплатного кода. Вы не просили помощи с Perl или awk, вы просили кого-то написать вам бесплатный код. Также ваше описание проблемы неясно. Я согласен, что иногда количество отрицательных голосов не пропорционально другим аналогичным вопросам в других тегах.

TLP 26.08.2024 14:30

Если ваши вопросы настолько отвергаются, что ваши учетные записи закрываются, а вы все еще публикуете одни и те же вопросы с новой фальшивой учетной записью, вы, вероятно, 1) поступаете неправильно, 2) нарушаете TOS. Вам следует прочитать часто задаваемые вопросы и посмотреть, как вы можете искупить свою вину.

TLP 26.08.2024 14:33

Re: Правило 1: Как определить «строку», если она не является концом абзаца? Конец предложения? Разрыв строки? Правило 2: Что вы имеете в виду иначе? Если это не однобуквенное слово? Если это не конец абзаца? Если это не конец строки? Чем отличаются «переместить на следующую строку» и «переместить на следующую строку»? Правило 3: Дефисы такие же, как правило 2? Вам действительно не следует предъявлять друг другу требования. Значит, дефисы тоже переносятся на следующую строку? Вы видите, как это просто сбивает с толку? То есть все будет перенесено на следующую строку?

TLP 26.08.2024 14:41

@TLP Извините, я не хочу тратить время на споры об этом. Что касается вашего второго комментария: Хорошо, позвольте мне исправить/уточнить эти вещи.

nick 26.08.2024 14:42

Я не спорю, я просто даю вам обратную связь на ваши комментарии и ваш вопрос. Извините, если было похоже на спор, я просто говорю прямо.

TLP 26.08.2024 14:44

@nick сайт (или, по крайней мере, теги, которые вы здесь использовали) существует для того, чтобы помочь людям с их кодом, поэтому, когда вы публикуете вопрос без кода, вы можете ожидать, что он соберет много отрицательных голосов и будет закрыт. Люди, отвечающие на такие вопросы, также часто привлекают отрицательные голоса к своим ответам. См. stackoverflow.com/help/on-topic и Как задавать, а также примеры хороших вопросов, на которые было проголосовано и на которые даны ответы. Вот почему я дал вам отправную точку в awk, чтобы вы могли опираться на нее, а затем задать вопрос по своему коду позже, если вы застрянете.

Ed Morton 26.08.2024 15:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
11
104
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Начало реализации только вашего первого правила

Правило 1: Перемещается каждое однобуквенное слово, если оно оказалось в конце строки и эта строка не является последней строкой абзаца. на следующую строку.

и предполагая, что абзацы разделены пустыми строками, используя GNU awk для границ слов \< и третий аргумент match():

$ awk '
    BEGIN { FS=OFS=RS; ORS=RS RS; RS = "" }
    {
        for ( i=1; i<NF; i++ ) {
            $i = saved $i
            if ( match($i, /(.*)\<([[:alpha:]])$/, a) ) {
                $i = a[1]
                saved = a[2] " "
            }
            else {
                saved = ""
            }
        }
        print
    }
' file
Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do
a eiusmod tempor incididunt ut labore et dolore magna aliqua. Do b
c quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
---minim a b veniam, quis nostrud exercitation ullamco laboris d.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do
a eiusmod tempor incididunt ut labore et dolore magna aliqua. Do b
c quis autem vel eum iure reprehenderit qui in ea voluptate velit esse
---minim a b veniam, quis nostrud exercitation ullamco laboris d.

Для получения дополнительной информации об awk приобретите книгу Арнольда Роббинса «Эффективное программирование на AWK, 5-е издание».

Ответ принят как подходящий

Используйте Perl, вы можете загружать свои данные в режиме абзаца. в качестве примера текста я использую \n , чтобы разделить каждый абзац, затем выполняю несколько операций s/pattern/replacement/ над каждым абзацем, чтобы построить правила, см. ниже:

perl -lpe '
    BEGIN{ $/ = "\n  " }                 # setup RS 
    s/ (\w(?: \w)*)\n/\n$1 /g;         # rule-1: 1+ consecutive single-char words followed by newline switched to the next line  
    s/ (\w{2,}(?: \w)+[?.!])$/\n$1/;   # rule-2: 1+ consecutive single-char words at end of para(trailing with `.` or `?` or `!`)
    s/ (\w+)\n(?=---)/\n$1/g;          # rule-3: rule for `---`
    s/^ */  /                          # fix the missing leading spaces for paragraphs
' file

Для вашего примера текста это дает:

  Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do
a eiusmod tempor incididunt ut labore et dolore magna aliqua. Do
b c quis autem vel eum iure reprehenderit qui in ea voluptate velit
esse---minim a b veniam, quis nostrud exercitation ullamco
laboris d.
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, satoru do
a eiusmod tempor incididunt ut labore et dolore magna aliqua. Do
b c quis autem vel eum iure reprehenderit qui in ea voluptate velit
esse---minim a b veniam, quis nostrud exercitation ullamco
laboris d.

Большое спасибо, Лихао!

nick 26.08.2024 23:33

Это дает результат вашего ввода, но я не знаю, соответствует ли он вашему намерению.

perl -0777ple '
    s/\s+(\w(?:\s+\w)*[.]?)\n(?!  |\z)/\n$1 /g;     # rule 1
    s/\s+(\w\w+(?:\s+\w)+[.]?)\n(?=  |\z)/\n$1\n/g; # rule 2
    s/\s+(\w\w+(?:\s+\w)*)\n(---)/\n$1$2/g;         # rule 3
' example.txt

Привет, Джонс. Это работает почти идеально, за исключением того, что laboris d. в конце второго абзаца не перенесен на следующую строку. В чем может быть причина?

nick 26.08.2024 16:58

Это означает, что файл, который вы тестируете, отличается от примера, который вы указали в вопросе (абзацы начинаются со строки с отступом в два пробела). Возможно, вы добавили лишние пустые строки в конец файла, который пробовали.

jhnc 26.08.2024 17:25

Я только что дважды проверил. Входной файл: pastebin.com/raw/dM7d6E79 . Выходной файл: pastebin.com/raw/5MJMMXk3 . Однако, если во входном файле после текста есть пустая строка, вывод правильный: Pastebin.com/raw/8jHnGMPc

nick 26.08.2024 21:09

POSIX требует, чтобы текстовые файлы заканчивались новой строкой. То же самое относится и к этому коду (см. \n(?! |\z)). Вы можете изменить регулярное выражение для обработки нетекстовых файлов и окончаний строк DOS.

jhnc 26.08.2024 22:27

Другие вопросы по теме