Вот пример текста:
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.
для правила 2, пожалуйста, уточните, что вы подразумеваете под ближайшим словом... перед одной буквой? после единственной буквы? что-то еще? также рассмотрите возможность обновления вопроса, чтобы определить абзац для первого набора данных... я предполагаю, что это что-то вроде starts with an indent
(пробелы или табуляция) и ends prior to next indented line
(или конец ввода)
пожалуйста, обновите вопрос, указав ваши последние попытки кодирования и (неправильные) результаты, полученные указанным кодом.
Спасибо всем, сегодня, когда приду домой, попробую предложенные решения. Не знаю, почему за вопрос проголосовали шесть раз. Были времена, когда я регулярно отвечал на вопросы по HTML/CSS и голосовал только против людей, которые публиковали свои вопросы, даже не пытаясь использовать заглавные буквы и правильную пунктуацию.
Обычно вопросы таких невежественных людей понижались до -1 или -2, иногда -3, но никогда ниже этого значения. Не уверен, что заслуживаю большего. Проблема с отрицательными голосами в том, что аккаунт могут заблокировать, и всё. Мои учетные записи были заблокированы дважды в этом году и ни разу за предыдущие 15 лет использования Stack Overflow. Здесь действительно что-то изменилось...
@nick Я бы сказал, что люди из тега Perl обижаются на людей, которые хотят бесплатного кода. Вы не просили помощи с Perl или awk, вы просили кого-то написать вам бесплатный код. Также ваше описание проблемы неясно. Я согласен, что иногда количество отрицательных голосов не пропорционально другим аналогичным вопросам в других тегах.
Если ваши вопросы настолько отвергаются, что ваши учетные записи закрываются, а вы все еще публикуете одни и те же вопросы с новой фальшивой учетной записью, вы, вероятно, 1) поступаете неправильно, 2) нарушаете TOS. Вам следует прочитать часто задаваемые вопросы и посмотреть, как вы можете искупить свою вину.
Re: Правило 1: Как определить «строку», если она не является концом абзаца? Конец предложения? Разрыв строки? Правило 2: Что вы имеете в виду иначе? Если это не однобуквенное слово? Если это не конец абзаца? Если это не конец строки? Чем отличаются «переместить на следующую строку» и «переместить на следующую строку»? Правило 3: Дефисы такие же, как правило 2? Вам действительно не следует предъявлять друг другу требования. Значит, дефисы тоже переносятся на следующую строку? Вы видите, как это просто сбивает с толку? То есть все будет перенесено на следующую строку?
@TLP Извините, я не хочу тратить время на споры об этом. Что касается вашего второго комментария: Хорошо, позвольте мне исправить/уточнить эти вещи.
Я не спорю, я просто даю вам обратную связь на ваши комментарии и ваш вопрос. Извините, если было похоже на спор, я просто говорю прямо.
@nick сайт (или, по крайней мере, теги, которые вы здесь использовали) существует для того, чтобы помочь людям с их кодом, поэтому, когда вы публикуете вопрос без кода, вы можете ожидать, что он соберет много отрицательных голосов и будет закрыт. Люди, отвечающие на такие вопросы, также часто привлекают отрицательные голоса к своим ответам. См. stackoverflow.com/help/on-topic и Как задавать, а также примеры хороших вопросов, на которые было проголосовано и на которые даны ответы. Вот почему я дал вам отправную точку в awk, чтобы вы могли опираться на нее, а затем задать вопрос по своему коду позже, если вы застрянете.
Начало реализации только вашего первого правила
Правило 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.
Большое спасибо, Лихао!
Это дает результат вашего ввода, но я не знаю, соответствует ли он вашему намерению.
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.
в конце второго абзаца не перенесен на следующую строку. В чем может быть причина?
Это означает, что файл, который вы тестируете, отличается от примера, который вы указали в вопросе (абзацы начинаются со строки с отступом в два пробела). Возможно, вы добавили лишние пустые строки в конец файла, который пробовали.
Я только что дважды проверил. Входной файл: pastebin.com/raw/dM7d6E79 . Выходной файл: pastebin.com/raw/5MJMMXk3 . Однако, если во входном файле после текста есть пустая строка, вывод правильный: Pastebin.com/raw/8jHnGMPc
POSIX требует, чтобы текстовые файлы заканчивались новой строкой. То же самое относится и к этому коду (см. \n(?! |\z)
). Вы можете изменить регулярное выражение для обработки нетекстовых файлов и окончаний строк DOS.
почему
do a
не перешёл на следующую строку, ведьdo
содержит как минимум 2 буквы? почему тыb c
перешел на следующую строку, ведь вb
нет хотя бы 2 букв?