Как я могу исправить разрывы линий в неправильных местах?

11

Мой текстовый файл выглядит так:

This is one
sentence that is broken.
However this is a good one.
And this
one is
somehow, broken into
many.

Я хочу удалить завершающий символ новой строки для любой строки, за которой следует строка, начинающаяся со строчной буквы.

Так что это должно быть:

This is one sentence that is broken.
However this is a good one.
And this one is somehow, broken into many.

Как я могу это сделать?

Изменить: Здесь есть несколько действительно хороших ответов, но я решил принять первый, который работал и был самым ранним. Большое спасибо всем!


источник
1
Латекс? Проблема в том, что вы действительно не устанавливаете правила правильного разбиения предложения. Вы хотите поместить все до пунктуации конца предложения, включая одну строку? Но что, если у вас есть длинное предложение, и оно выходит за пределы вашего окна дисплея?
jamesqf
1
Интересно, что вы действительно пытаетесь решить? Возможно, вам следует использовать форматирование уценки?
Wildcard
@JeffSchaller Спасибо за напоминание! Я как-то пропустил. :)

Ответы:

7

пытаться

awk '$NF !~ /\.$/ { printf "%s ",$0 ; next ; } {print;}' file

где

  • $NF !~ /\.$/ строка соответствия, где последний элемент не заканчивается точкой,
  • { printf "%s ",$0 напечатать эту строку с пробелом, без перевода строки,
  • next ; } получить следующую строку,
  • {print;} и распечатай это.

Я уверен, что будет sedвариант.

Примечание: это будет работать со строкой, заканчивающейся точкой, однако условие в предложениях, начинающихся с заглавной буквы, не будет объединено. Смотрите ответ Стефана Шазеля.

Archemar
источник
Если вам нравится умный (многие этого не делают)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thompson_085
10

С awk:

awk -v ORS= '{print (NR == 1 ? "" : /^[[:lower:]]/ ? " " : RS) $0}
             END {if (NR) print RS}'

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

Стефан Шазелас
источник
Когда я запускаю это, некоторые пары слов объединяются. Например, And thisone issomehow, broken intomany.я не знаю, awkно нужно ли соединять строки <space>в дополнение к RS? Или это ошибка пользователя?
B Layer
@BLayer, хорошо заметили, спасибо. Должно быть исправлено сейчас.
Стефан
Нет проблем. Хотя интересно, откуда взялись 11 голосов. Должно быть, приятно, когда люди просто считают, что ты всегда прав. ;)
B Layer
4

В Perl:

#!/usr/bin/perl -w
use strict;
my $input = join("", <>);
$input =~ s/\n([a-z])/ $1/g;
print $input;

Технически вы хотели заменить «символ новой строки с последующей строчной буквой» на «пробел и строчная буква», что и делает ядро ​​приведенного выше сценария perl:

  1. Читайте во входных данных в строку input.
  2. Обновите inputпеременную, чтобы она стала результатом операции поиска и замены.
  3. Напечатайте новое значение.
Джефф Шаллер
источник
1
хороший!! переведено на одну строку perl -0777 -pe 's/\n([a-z])/ $1/g'и может быть аналогичным образом выполнено с помощью GNU sed как sed -zE 's/\n([a-z])/ \1/g'(при условии, что ввод не имеет нулевых символов)
Sundeep
3
@Sundeep, или perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'чтобы он не ограничивался буквами ASCII.
Стефан
4

С помощью sedвы можете использовать N;P;Dцикл (чтобы всегда иметь две строки в шаблонном пространстве, и если первый символ после новой строки строчный, то заменить новую строку пробелом) и test - таким образом, после каждой sзамены вы перезапускаете цикл:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile
don_crissti
источник
1
Я думаю, что вижу, что здесь происходит, но расширенный ответ поможет тем из нас, кто не очень часто использует циклы sed и шаблоны.
Джо
@Joe - что ты имеешь в виду под "не очень часто использовать пространство шаблонов" ? Вот где происходят почти все операции - пространство хранения - это «пространство хранения» - вы ничего не можете сделать с данными, пока они там. Во всяком случае, я подробно объяснил, как работает N;P;Dцикл, поэтому я не буду его повторять. Разница здесь в tтом, что самое главное - проверить, было ли что-то заменено или нет - если тест пройден успешно, мы переходим к началу скрипта, иначе это означает, что ничего не было заменено и P;Dвыполнено. Дайте мне знать, если это все еще неясно.
don_crissti
3

Использование sedи fmt:

$ sed -e '1n; s/^[[:upper:]]/\n&/' input.txt | fmt
This is one sentence that is broken.

However this is a good one.

And this one is somehow, broken into many.

Сценарий sed вставляет новую строку перед каждой строкой, которая начинается с заглавной буквы (за исключением самой первой строки ввода). sedЗатем выводится fmtрезультат, чтобы переформатировать результирующие абзацы.

В качестве альтернативы используйте, parесли он у вас установлен. Это еще одно средство переформатирования абзацев, но гораздо более функциональное, чем fmtс множеством других функций и опций.

Обратите внимание, что между каждым абзацем будет пустая строка. Параграфы должны быть отделены друг от друга хотя бы одной пустой строкой. Без пустых строк весь ваш входной образец переформатируется как один абзац из нескольких предложений, например:

$ fmt input.txt
This is one sentence that is broken.  However this is a good one.
And this one is somehow, broken into many.

Если вам нужно удалить пустые строки после переформатирования, просто передайте их sedснова, но это удалит ВСЕ пустые строки, включая те, которые могли быть в исходном вводе. например

$ sed -e '1n; s/^[[:upper:]]/\n&/' input.txt | fmt | sed -e '/^$/d'
This is one sentence that is broken.
However this is a good one.
And this one is somehow, broken into many.
саз
источник
3

Еще один способ сделать это:

perl -lpe '$\ = /\.$/ ? $/ : $"' data

где: $\=> ORS, $/=> IRS= \n, $"=space

perl -pe '$_ .= <>, eof or redo if s/[^.]\K\n/ /' data

sed -e '
   :a
      /\.$/!N
      s/\n/ /
   ta
' data

источник
2

Python 3

import re
print(re.sub(r'\n([a-z])', r' \1', open('file.txt').read(), flags=re.MULTILINE))

Это то же регулярное выражение / замена, что и ответ Джеффа

wjandrea
источник