Jak naprawić linie przerywane w niewłaściwych miejscach?

11

Mój plik tekstowy wygląda następująco:

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

Chcę usunąć końcowy znak nowej linii dla każdej linii, po której następuje linia rozpoczynająca się od małej litery.

Powinno to być:

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

Jak mogę to zrobić?

Edycja: Jest tu kilka naprawdę dobrych odpowiedzi, ale zdecydowałem się zaakceptować pierwszą, która zadziałała i była najwcześniejsza. Dziękuję bardzo wszystkim!


źródło
1
Lateks? Problem polega na tym, że tak naprawdę nie określasz zasad prawidłowego dzielenia zdań. Czy chcesz umieścić wszystko w jednym wierszu łącznie z interpunkcją końca zdania? Ale co, jeśli masz długie zdanie, które biegnie poza krawędź okna wyświetlacza?
jamesqf
1
Zastanawiam się, co naprawdę próbujesz rozwiązać? Być może powinieneś użyć formatowania przecen?
Wildcard
@JeffSchaller Dzięki za przypomnienie! Jakoś przegapiłem. :)

Odpowiedzi:

7

próbować

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

gdzie

  • $NF !~ /\.$/ dopasuj linię, w której ostatni element nie kończy się kropką,
  • { printf "%s ",$0 wydrukuj ten wiersz ze spacją i bez podawania wiersza,
  • next ; } pobierz następną linię,
  • {print;} i wydrukuj to.

Jestem pewien, że będzie sedopcja.

Uwaga: będzie to działać z linią kończącą się kropką, jednak warunek w zdaniach rozpoczynających się od dużej litery nie zostanie scalony. Zobacz odpowiedź Stéphane'a Chazelasa.

Archemar
źródło
Jeśli lubisz sprytne (wielu nie)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thompson_085
10

Z awk:

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

Oznacza to, że nie dołączaj separatora rekordów do każdej linii (pusty ORS). Ale wstaw separator rekordów przed bieżącym wierszem, jeśli nie w pierwszym wierszu, a bieżący wiersz nie zaczyna się od małej litery. W przeciwnym razie wstaw znak spacji zamiast pierwszego wiersza.

Stéphane Chazelas
źródło
Kiedy to uruchamiam, niektóre pary słów są łączone. Na przykład And thisone issomehow, broken intomany.nie wiem, awkale należy połączyć linie <space>oprócz RS? Czy ten błąd użytkownika?
B Warstwa
@BLayer, dobrze zauważony, dzięki. Powinien zostać teraz naprawiony.
Stéphane Chazelas,
Nie ma problemu. Chociaż zastanawia się, skąd wzięło się 11 głosów poparcia. To musi być miłe, gdy ludzie zakładają, że zawsze masz rację. ;)
B Layer
4

W perlu:

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

Technicznie rzecz biorąc, chciałeś zastąpić „newline, po którym małymi literami”, „spacją i małą literą”, co robi rdzeń powyższego skryptu perl:

  1. Wczytaj dane wejściowe do ciągu input.
  2. Zaktualizuj inputzmienną, aby była wynikiem operacji wyszukiwania i zamiany.
  3. Wydrukuj nową wartość.
Jeff Schaller
źródło
1
dobry!! przetłumaczone na jednowierszowe, perl -0777 -pe 's/\n([a-z])/ $1/g'i podobnie można to zrobić za pomocą GNU sed jako sed -zE 's/\n([a-z])/ \1/g'(zakładając, że dane wejściowe nie mają znaków zerowych)
Sundeep
3
@ Sundeep, lub perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'aby nie ograniczać się do liter ASCII.
Stéphane Chazelas
4

Ze sedmożna użyć N;P;Dcyklu (tak aby zawsze mieć dwie linie w przestrzeni wzorca, a jeśli pierwszy znak po znaku nowej linii jest małe litery następnie zastąpić przełamane spacją) oraz tEst - w ten sposób po każdym substitution uruchomieniu cyklu:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile
don_crissti
źródło
1
Myślę, że widzę, co się tutaj dzieje, ale rozszerzona odpowiedź pomogłaby tym z nas, którzy nie używają często pętli sed i przestrzeni wzorów.
Joe
@Joe - co rozumiesz przez „nieużywanie przestrzeni wzorów bardzo często” ? Właśnie tam odbywają się prawie wszystkie operacje - przestrzeń wstrzymania jest „przestrzenią pamięci” - nie można nic zrobić z danymi, gdy są one dostępne. W każdym razie, mam szczegółowo wyjaśnione jak cykl działa tu więc nie będę się nad nim ponownie. Różnica polega na tym, że - aby sprawdzić, czy coś zostało zamienione, czy nie - jeśli test się powiedzie, przechodzimy na początek skryptu, w przeciwnym razie oznacza to, że nic nie zostało zastąpione i jest wykonywane. Daj mi znać, jeśli nadal jest niejasne. N;P;DtP;D
don_crissti
3

Korzystanie sedi 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.

Skrypt sed wstawia nowy wiersz przed każdym wierszem rozpoczynającym się od dużej litery (z wyjątkiem pierwszego wiersza wprowadzania). sedDane wyjściowe są następnie przesyłane w fmtcelu sformatowania powstałych akapitów.

Alternatywnie użyj, parjeśli masz zainstalowany. To kolejny formatowanie akapitów, ale o wiele bardziej wydajny niż fmt, z wieloma dodatkowymi funkcjami i opcjami.

Zauważ, że pomiędzy każdym akapitem będzie pusta linia. Akapity powinny być oddzielone od siebie co najmniej jedną pustą linią. Bez pustych wierszy cała próbka wejściowa jest sformatowana jako pojedynczy akapit z wieloma zdaniami, np .:

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

Jeśli musisz usunąć puste linie po sedponownym sformatowaniu, po prostu przeciągnij je ponownie - ale spowoduje to usunięcie WSZYSTKICH pustych linii, w tym również tych, które mogły znajdować się w oryginalnym pliku wejściowym. na przykład

$ 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.
cas
źródło
3

Innym sposobem na to jest:

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

gdzie: $\=> ORS, $/=> IRS= \n, $"=space

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

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

źródło
2

Python 3

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

To jest to samo wyrażenie regularne / podstawienie co odpowiedź Jeffa

wjandrea
źródło