Perl: Помощь в настройке RS

Следующий скрипт (который создан частично в образовательных целях, и именно поэтому здесь используется не только Perl†, но также awk и sed‡)...

† Версия Perl — 5.34
awk и sed — это те, которые поставляются с macOS.

thisscript input.md output.txt
sed 's/[[:space:]]-[[:space:]]/---/g' $1 |
sed 's/[[:space:]]\{0,1\}—[[:space:]]\{0,1\}/---/g' |
sed 's/\\\*/†/g' |
sed 's/*///g' |
sed 's/\\\././g' |
sed 's/…/.../g' |
awk 'BEGIN{RS = "";ORS = "\n  "}1' |
fold -s -w 72 |
perl -C -lpe '
    BEGIN{ $/ = "\n  " }
    s/ (\w(?: \w)*)\r?\n/\n$1 /g;
    s/ (\w{2,}(?: \w)+[?.!])\s*$/\n$1/;
    s/ (\w+)\r?\n(?=---)/\n$1/g;
    s/^ */  /
' |
sed 's/[[:space:]]+//g' > $2

заключается в преобразовании типичного текста Markdown (учитывая, что текст достаточно простой, скажем, детской книжки о пиратах) во что-то более приятное на мой вкус.

Тест 1

Введите текст:

  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.

Выходной текст:

  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.

Как вы, возможно, заметили, часть Perl отвечает за перемещение любого однобуквенного слова на следующую строку. Есть и другие вещи, которые делает часть Perl, но для целей этого вопроса о Unix и Linux они не имеют значения. Нам нужно только знать, работает ли часть Perl или нет.

Тест 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.

Выходной текст должен быть таким же, как выходной текст первого теста, но это не так:

  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.

Как вы могли заметить, однобуквенные слова не были перемещены, то есть Perl не участвовал в обработке текста. Насколько я понимаю (я просто сказал, что нужно изучать Perl), это потому, что строка

BEGIN{ $/ = "\n  " }

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

BEGIN{ $/ = "\n  |\n\n" }

не помогло.

Что я делаю не так?

Можете ли вы показать нам желаемый результат? Как будет выглядеть правильный результат? Хотите, чтобы все однобуквенные слова начинались с новой строки? В первом примере вы перемещаете любые однобуквенные слова, находящиеся в конце строки, на новую строку. Хорошо, какие из них следует переместить во втором примере? Как ваш сценарий узнает, что нужно разделить строку на a слова «satoru do a», но не разделить ее на c слова «Do b c quis» или b слова «minim a b»?

terdon 28.08.2024 10:28

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

nick 28.08.2024 10:38

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

terdon 28.08.2024 10:42

@terdon Но в сценарии есть fold -s -w 72 перед perl. Если я правильно понимаю, perl должен принимать вывод fold, тогда как вывод fold представляет собой текст, который жестко перенесен в столбец 72. Может я что-то неправильно понял?

nick 28.08.2024 10:48

Вы правильно поняли, но посмотрите на вывод fold. Просто закомментируйте все, что стоит после fold в вашем скрипте, и запустите его. Вы увидите, что вместо Do b c\n у вас есть Do b c quis\n, так как же нам узнать, нужно ли добавить \n после c? Выходные данные существенно отличаются от двух входных примеров, поэтому вы не можете относиться к ним одинаково.

terdon 28.08.2024 10:53

@terdon Понятно, спасибо, но это не ответ на вопрос, почему скрипт не перемещает слово a в satoru do a (первая строка каждого абзаца). Насколько я понимаю, это небольшое изменение изменит форму следующих строк, и тогда вместо Do b c quis\n будет Do b c\n, и тогда мы можем ожидать тот же результат, что и в первом тесте. Не так ли?

nick 28.08.2024 11:26

У вас есть ответ, объясняющий, что: $/ не может быть регулярным выражением, а только определенной строкой, поэтому ваш \n |\n\n не означает «новую строку, за которой следует пробел ИЛИ две последовательные новые строки», он означает «новую строку, за которой следует пробел». , затем |, а затем две последовательные новые строки».

terdon 28.08.2024 11:34

@terdon Да, но это не сработает, даже если я заменю строку BEGIN{ $/ = "\n " } на BEGIN{ $/ = "\n\n" }. Теперь кажется, что он не содержит регулярных выражений, но все равно не работает.

nick 28.08.2024 11:47

Почему \n\n сработает? Разве вы не смотрели на вывод fold, как я предлагал выше? К тому времени, как вы доберетесь до команды \n\n, perl исчезнет, ​​ваш awk удалит их. Пожалуйста, задайте новый вопрос здесь или в Unix & Linux и с самого начала объясните, для чего вам действительно нужен скрипт. На этот вопрос о том, почему подход $/ не удался, получен ответ.

terdon 28.08.2024 12:05

@terdon Хорошо, извини, ты прав, и замена BEGIN{ $/ = "\n " } на BEGIN{ $/ = "\n\n" } была глупой идеей. Но я так и не понимаю, почему скрипт не перемещается a в satoru do a.

nick 28.08.2024 12:26

Давайте продолжим обсуждение в чате.

terdon 28.08.2024 12:28
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

От perldoc perlvar (см. https://perldoc.pl/perlvar#$/)

    $/      The input record separator, newline by default. This influences
            Perl's idea of what a "line" is. Works like awk's RS variable,
            including treating empty lines as a terminator if set to the
            null string (an empty line cannot contain any spaces or tabs).
            You may set it to a multi-character string to match a
            multi-character terminator, or to "undef" to read through the
            end of file. Setting it to "\n\n" means something slightly
            different than setting to "", if the file contains consecutive
            empty lines. Setting to "" will treat two or more consecutive
            empty lines as a single empty line. Setting to "\n\n" will
            blindly assume that the next input character belongs to the next
            paragraph, even if it's a newline.

                local $/;           # enable "slurp" mode
                local $_ = <FH>;    # whole file now here
                s/\n[ \t]+/ /g;

            Remember: the value of $/ is a string, not a regex. awk has to
            be better for something. :-)

Обратите внимание на последнее предложение.

Скрипт по-прежнему не работает, но я думаю, было бы справедливо сказать, что на вопрос дан ответ, так что спасибо.

nick 28.08.2024 22:56

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