Come posso riparare le linee spezzate in posti sbagliati?


11

Il mio file di testo è simile al seguente:

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

Voglio rimuovere il carattere di nuova riga finale per qualsiasi riga seguita da una riga che inizia con una lettera minuscola.

Quindi questo dovrebbe essere:

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

Come posso fare questo?

Modifica: ci sono alcune risposte davvero buone qui, ma ho scelto di accettare la prima che ha funzionato ed è stata la prima. Grazie mille a tutti!


1
LaTeX? Il problema è che in realtà non si definiscono le regole per una corretta infrazione della frase. Vuoi mettere tutto fino alla punteggiatura di fine frase inclusa, compresa una riga? Ma cosa succede se si dispone di una frase lunga e scappa dal bordo della finestra del display?
jamesqf,

1
Mi chiedo cosa stai davvero cercando di risolvere? Forse dovresti usare la formattazione markdown?
Wildcard il

@JeffSchaller Grazie per il promemoria! Mi ero perso in qualche modo. :)

Risposte:


7

provare

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

dove

  • $NF !~ /\.$/ linea di corrispondenza in cui l'ultimo elemento non termina con un punto,
  • { printf "%s ",$0 stampa questa riga con uno spazio finale e nessun feed riga,
  • next ; } recuperare la riga successiva,
  • {print;} e stampalo.

Sono sicuro che ci sarà sedun'opzione.

Nota: funzionerà con la linea che termina con un punto, tuttavia la condizione nelle frasi che iniziano con la lettera maiuscola non verrà unita. Vedi la risposta di Stéphane Chazelas.


Se ti piace intelligente (molti non lo fanno)awk 'ORS=$NF~/\.$/?"\n":" "'
dave_thompson_085

10

Con awk:

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

Cioè, non aggiungere il separatore di record a ciascuna riga (ORS vuoto). Ma anteponi un separatore di record prima della riga corrente se non sulla prima riga e la riga corrente non inizia con una lettera minuscola. Altrimenti anteponi invece uno spazio, tranne nella prima riga.


Quando eseguo questo alcune coppie di parole sono concatenate. Ad esempio And thisone issomehow, broken intomany., non lo so, awkma le linee dovrebbero essere unite <space>oltre a RS? O è questo errore utente?
B Layer

@BLayer, ben notato, grazie. Ora dovrebbe essere risolto.
Stéphane Chazelas,

Nessun problema. Anche se ci si chiede da dove provengano gli 11 voti. Deve essere bello avere delle persone che credono che tu abbia sempre ragione. ;)
B Layer

4

In perl:

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

Tecnicamente volevi sostituire "newline seguito da una lettera minuscola" con "spazio e quella lettera minuscola", che è ciò che fa il nucleo dello script perl sopra:

  1. Leggi nell'input su una stringa input.
  2. Aggiorna la inputvariabile in modo che sia il risultato dell'operazione di ricerca e sostituzione.
  3. Stampa il nuovo valore.

1
buona !! tradotto in una riga, perl -0777 -pe 's/\n([a-z])/ $1/g'e può essere fatto allo stesso modo con GNU sed as sed -zE 's/\n([a-z])/ \1/g'(supponendo che l'input non abbia caratteri null)
Sundeep,

3
@Sundeep, o perl -Mopen=locale -0777 -pe 's/\n(?=[[:lower:]])/ /g'per non essere limitato alle lettere ASCII.
Stéphane Chazelas,

4

Con sedte potresti usare un N;P;Dciclo (in modo da avere sempre due linee nello spazio del modello e se il primo carattere dopo la nuova riga è minuscolo, sostituisci la nuova riga con uno spazio) e un test - in questo modo dopo ogni substitution riavvii il ciclo:

sed -e :t -e '$!N;/\n[[:lower:]]/s/\n/ /;tt' -e 'P;D' infile

1
Penso di vedere cosa sta succedendo qui, ma una risposta espansa aiuterebbe quelli di noi che non usano anelli di sed e pattern spazi molto spesso.
Joe,

@Joe - cosa intendi per "non usare lo spazio del pattern molto spesso" ? È lì che avvengono quasi tutte le operazioni - lo spazio di attesa è uno "spazio di archiviazione" - non puoi fare nulla con i dati mentre è lì. Ad ogni modo, ho spiegato in dettaglio come funziona un N;P;Dciclo qui, quindi non lo ripeterò più. La differenza qui è l' test - per verificare se qualcosa è stato sostituito o no - se il test ha esito positivo, ci ramifichiamo all'inizio dello script, altrimenti significa che nulla è stato sostituito e P;Dviene eseguito. Fammi sapere se non è ancora chiaro.
don_crissti,

3

Utilizzando sede 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.

Lo script sed inserisce una nuova riga prima di ogni riga che inizia con una lettera maiuscola (ad eccezione della prima riga di input). sedL'output viene quindi reindirizzato fmtper riformattare i paragrafi risultanti.

In alternativa, utilizzare parse è installato. È un altro riformattatore di paragrafi, ma molto più capace di fmt, con molte più funzioni e opzioni.

Si noti che ci sarà una linea vuota tra ogni paragrafo. I paragrafi devono essere separati l'uno dall'altro da almeno una riga vuota. Senza le righe vuote, l'intero campione di input viene riformattato come un singolo paragrafo a più frasi, ad esempio:

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

Se è necessario rimuovere le righe vuote dopo aver riformattato, reindirizzarle di sednuovo, ma ciò rimuoverà TUTTE le righe vuote, comprese quelle eventualmente presenti nell'input originale. per esempio

$ 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

Un altro modo per farlo è:

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

dove: $\=> 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))

Questa è la stessa regex / sostituzione della risposta di Jeff

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.