Wie man unter Linux Sätze in separate Zeilen setzt


7

Ich habe die Aufgabe, Sätze in einer Textdatei in separate Zeilen zu setzen. So etwas funktioniert fast:

cat file.txt | tr '.' '\n'

Aber ich möchte keine Punkte, Fragezeichen und Ausrufezeichen aus meinen Sätzen verlieren. Wie kann ich das zum Laufen bringen?


2
Bitte zeigen Sie uns ein Beispiel Ihrer Eingabedatei und Ihrer gewünschten Ausgabe.
Terdon

2
Befürchten Sie Zeilenumbrüche nach Satzzeichen in Sätzen? ZB lateinische Abkürzungen (zB "zB"), zitierte Sätze (zB "Was!", Riefen sie aus), Notationen (z. B. "3!
Charles Stewart

3
Dies ist eine sehr schwierige Sache, um richtig zu machen. Sie müssen entweder den Umfang der Frage viel enger und genauer definieren oder ein Programm entwickeln, das Englisch wirklich verstehen kann . Drei Herausforderungen, denen bisher keine der Antworten begegnet ist: (1) Die Abkürzung „Dr.“ könnte an das nächste Token (Wort / Name) oder das vorherige gebunden sein . Angesichts des Textes „Dr. Oz lebt am Seeufer Dr. Phil ist obdachlos. “Es ist sehr schwer zu erkennen, dass„ Phil “einen neuen Satz beginnt. … (Fortsetzung)
Scott

1
(Fortsetzung)… (2) Zitate und Klammern. He asked, “What should I bring?” She replied, “A bottle of wine would be nice.” Then she hung up.Richtiges Verhalten ist nach dem .oder zu brechen ?. Ebenso „Verwenden awk. (Es ist POSIX-konform.) Oder verwenden Sie mygawk. “, Wobei Sie nicht zwischen„ konform “wechseln müssen. und der ")". (3) Manchmal kommt "..." innerhalb eines Satzes vor. Auch (4) Angesichts des Textes: „Oh! Ich habe vergessen, den Herd auszuschalten. “Einige Leute halten dies möglicherweise für einen Satz. "Oh!" ist eindeutig kein Satz, da er weder Subjekt noch Verb enthält. Das ist aber subjektiv.
Scott

Ich sehe nachträglich , dass Charles bereits einige dieser Punkte angesprochen hat. +1 für “ n ! repräsentiert n Fakultät. ”
Scott

Antworten:


16

Ich kann nicht sicher sein, ohne ein aktuelles Beispiel Ihrer Daten zu sehen, aber was Sie wahrscheinlich suchen, ist das Hinzufügen einer neuen Zeile nach jedem Auftreten von ., !und ?. Ich weiß nicht, wie Sie mit Semikolons ( ;) umgehen sollen, da sie nicht wirklich das Ende eines Satzes markieren. Das liegt an dir.

Wie auch immer, Sie könnten versuchen sed:

$ echo 'This is a sentence! And so is this. And this one?' | 
    sed 's/[.!?]  */&\n/g' 
This is a sentence! 
And so is this. 
And this one?

Das s///ist der Substitutionsoperator. Sein allgemeines Format ist , s/pat/replacementund es wird ersetzt patmit replacement. Das gam Ende macht es den Ersatz bei allen Vorkommen von pat. Ohne sie würde es beim ersten aufhören. Das &ist ein spezielles sedKonstrukt, das "was auch immer übereinstimmte" bedeutet. Also, hier wir ersetzen alle ., !oder ?mit dem, was angepasst wurde und eine neue Zeile.

Wenn Ihr Text Abkürzungen wie enthalten e.g.kann, möchten Sie ihn möglicherweise nur ersetzen, wenn der nächste Buchstabe ein GROSSBUCHSTABEN ist:

$ echo 'This is a sentence! And so is this. And this one? Negative, i.e. no.' | sed 's/\([.!?]\) \([[:upper:]]\)/\1\n\2/g' 
This is a sentence!
And so is this.
And this one?
Negative, i.e. no.

Beachten Sie, dass dies nicht mit Sätzen wie umgehen wird Dr. Jones said hello.richtig , da es , dass die davon ausgehen , .nachdem Drdefiniert ein Satz gegeben , dass der nächste Buchstabe aktiviert ist. Wir nähern uns jetzt jedoch einer Komplexität, die weit über das einfache Q & A-Format hinausgeht und tatsächlich einen vollständigen Parser für natürliche Sprachen erfordert.


1
+1 für den ersten Antwortenden, der (a) das Leerzeichen nach dem Interpunktionszeichen erfasst (und entfernt) und (b) das gam Ende enthält (da ein kurzer Satz vollständig in einer Zeile enthalten sein kann, mit anderen Dingen vor und nach). Wenn ich Ihnen +2 geben könnte, hätte ich es getan, wenn Sie nur gesagt hätten (space)*- da einige von uns alten Leuten immer noch so tippen, wie es uns beigebracht wurde: Sätze durch zwei Leerzeichen trennen. (Auch wenn der eingegebene Text die Ausgabe von etwas wie RUNOFF ist roff, oder nroffzusätzliche Leerzeichen verwendet werden könnten, um eine Textausrichtung zu erreichen.)
Scott

Noch nie von diesem interessanten Zwei-Räume-Konzept gehört
TheBlastOne

@ Scott danke, und sehr guter Punkt für das Matching space*, Antwort bearbeitet.
Terdon

@don_crissti wahr, danke. Ich habe zwei Leerzeichen hinzugefügt, wobei das zweite optional ist. Dies sollte funktionieren, solange ein Satz richtig geschrieben ist (mit einem Leerzeichen nach dem Satzzeichen) und keine leere Zeile hinzugefügt wird, es sei denn, die Eingabe enthält ein nachfolgendes Leerzeichen.
Terdon

2
@don_crissti verdammt, ich hatte nicht einmal an Abkürzungen gedacht. Sie könnten so etwas wie sed 's/\([.!?]\) \([[:upper:]]\)/\1\n\2/g'nur übereinstimmen, wenn das nächste Zeichen ein Großbuchstabe ist.
Terdon

6

Versuchen:

sed -e :1 -e 's/\([.?!]\)[[:blank:]]\{1,\}\([^[:blank:]]\)/\1\
\2/;t1'

Bei einer Eingabe wie:

Sentence 1. Sentence 1.2? Sentence 2!? Sentence 3.
Sentence 4... Sentence 5.

Es gibt:

Sentence 1.
Sentence 1.2?
Sentence 2!?
Sentence 3.
Sentence 4...
Sentence 5.

(und ist POSIX).


@mikeserv, nein ich wiederhole während es passt. Wie das Hinzufügen des gFlags zu, saber mit dem Zusatz, dass es beide .s in behandelt . . x.
Stéphane Chazelas

1
+1 für [[:blank:]]\{1,\}, obwohl es schön wäre, wenn Sie erklären würden, was Sie tun. Ich verstehe es, aber das OP gibt zu, ein Neuling zu sein.
Scott

2

Verwenden Sie sedstattdessen:

sed 's/\./\.\n/' file.txt

1
Sätze enden nicht nur mit Punkt. Auch UUoC .
Terdon

2

Die Aufgabe hat einige Fallstricke. Eine Option könnte sein:

sed 's/\([.?!;]\) */\1\n/g' file.txt

Dies ersetzt die Zeichen im angegebenen Zeichensatz ( [.?!;]fügen Sie einen Doppelpunkt hinzu oder entfernen Sie das Semikolon entsprechend Ihren Anforderungen), gefolgt von optionalen Leerzeichen ( *) durch das ersetzte Zeichen ( \1erweitert auf die Übereinstimmung zwischen \(und \)) und eine neue Zeile ( \n).


Stephane, ich denke, Sie müssten den \nmeisten der hier veröffentlichten Lösungen den Hinweis hinzufügen . (Ich habe das \?für bearbeitet *.)
Janis

+1 für den ersten Antwortenden (space)*.
Scott

1

Versuchen:

awk -F. '{ for (i=1;i<=NF;i++) printf "%s.\n",$i ;} ' < input_file > output_file

wo

  • awk verwendet .(Punkt) als Trennzeichen,
  • und Schleifen für jedes Feld, Drucken der Linie, ein Punkt eine neue Linie

Das passt nur zu Perioden. Was ist mit ?!? Außerdem müssen Sie den Abstand zwischen dem Punkt und dem nächsten Satz berücksichtigen.
Terdon

OP nur Punkt erwähnen.
Archemar

Nein, haben sie nicht: "Ich möchte keine Punkte, Fragezeichen und Ausrufezeichen aus meinen Sätzen verlieren."
Terdon

Was meinst du mit "ein Punkt eine neue Zeile"? "ein Punkt pro Zeilenumbruch"?
Peter Mortensen

1
@ Peter: Falls Sie dies aus noch nicht herausgefunden haben, vermute ich , dass Archemar bedeutete „die Zeile gedruckt wird , ein Punkt , und eine neue Zeile.“
Scott

1

Es gibt Leben außerhalb von Einzeilern ...

Satzteiler sind nie fertig, es gibt immer noch ein Detail zu reparieren: einen Perl-Multiliner!

#!/usr/bin/perl

use strict;
my $pont=qr{[.!?]+};                   ## pontuation
my $abrev=qr{\b(?:Pr|Dr|Mr|[A-Z])\.};  ## abreviations

$/="";   

while(<>){ chomp;                      ## for each paragraph,

  s/\h*\n\h*/ /g;                      ## remove \n
  s/($pont)\h+(\S)/$1\n$2/g;           ## pontuation+space
  s/($abrev)\n/$1 /g;                  ## undo \n after abreviations

  print "$_\n\n";
}

also mit:

A single ‘-’ operand is not really an option ! It stands for
standard input. Or for standard output ? For example:
smth -’ reads from stdin; and is equal
to plain smth’... Could it appear as any operand that
requires a file name ? Certainly !

Robert L. Stevenson wrote  Dr. Jekyll and Mr. Hyde. Back in 12.12.1886

the end

Die Ausgabe ist:

A single ‘-’ operand is not really an option !
It stands for standard input.
Or for standard output ?
For example: smth -’ reads from stdin; and is equal to plain smth’...
Could it appear as any operand that requires a file name ?
Certainly !

Robert L. Stevenson wrote  Dr. Jekyll and Mr. Hyde.
Back in 12.12.1886

the end

Sehr gut! Sie sind die einzige Person, die das heikle Thema der Abkürzungen angegriffen hat (z. B. „Mr. Spock“). Aber (1) Es ist fast unmöglich, eine vollständige Liste von Abkürzungen zu erstellen, die mit einem Punkt enden. Offensichtliche, die Sie verpasst haben, sind „Frau“, „Frau“ (eine Frau mit nicht näher bezeichnetem Familienstand), „St“ (Heilige) und „Prof“ (Professor). Ich erkenne "Pr" nicht - verwenden Sie das für "Professor"? … (Fortsetzung)
Scott

(Fortsetzung)… Einige andere, die Sie verpasst haben, sind militärische Reihen (Gen, Col, Maj, Capt,…), „Drs“ (der Plural von „Dr“, wie in „Drs. Oz und Phil“), Kompassrichtungen (N, S, E, W) und "Nein" bedeuten entweder "Nord" oder "Zahl". (2) Umgekehrt geht Ihr Code davon aus, dass "Dr." ist nie das Ende eines Satzes, also wird „ Oak St. wird Lakeside Dr. Das Lake Chalet befindet sich zu Ihrer Rechten. "Wird als" Oak St. "gerendert // "wird zu Lakeside Dr. Das Lake Chalet befindet sich zu Ihrer Rechten." … (Fortsetzung)
Scott

(Fortsetzung)… (3) Ebenso wird davon ausgegangen, dass ein einzelner Buchstabe niemals das letzte Wort eines Satzes sein kann. Überlegen Sie: „Wer geht? John und ich. Wann? Morgen." Ihr Code denkt, dass "John und ich. Wann?" ist alles ein Satz. Ebenso: "Der 17. Buchstabe des Alphabets ist Q. Der 18. Buchstabe des Alphabets ist R.", "Shakespeare hat ein Stück über Henry V geschrieben ..." "Haben Sie von Malcolm X gehört? … “(4) Siehe auch meinen Kommentar zur Frage.
Scott

@ Scott, danke für die Kommentare, Fehlerberichte. Wie ich am Anfang behauptete: Sie sind nie bereit. Der (lange) Weg ist, Schritt für Schritt zu versuchen, die Präzision zu erhöhen, da wir wissen, dass wir weit von 100% entfernt sind. Mein sentSplitter für portugiesische Korpora enthält viel mehr Zeilen (einschließlich Optionen zum Verarbeiten von LaTex-Mathematik, Schachnotationsspielen, URLs, E-Mails usw.). Diese Aufgabe erfordert eindeutig Tests, Bewertungen, Lerntechniken ..., Multifunktion, Modularität usw.
JJoao

-1
sed 's/\([.!?]  *\)\{0,1\}/\1\\/g' <infile | xargs printf %s\\n

Ich hatte dieses Ding w / foldvor - was schnell war - aber ich erkannte, dass ich das gleiche w / xargsw tun konnte , ohne Eingaben vorverarbeiten oder sedVerzweigungsschleifen implementieren zu müssen, wenn ich nur alles, was kein terminierendes Zeichen war, einem Backslash entkam alle nachfolgenden Leerzeichen.

Die obige Anweisung entspricht also sedentweder der Nullzeichenfolge oder einer Abschlusssequenz für jedes Zeichen (nicht in der Sequenz) , das bei der Eingabe auftritt. Auf der rechten Seite wird sedentweder die Nullzeichenfolge oder die Abschlusssequenz durch for ersetzt \1und anschließend ein Backslash eingefügt. Das Ergebnis ist, dass jedes Zeichen außer einem, .!?wenn mindestens ein Leerzeichen folgt, einen \Backslash-Escape-Effekt erhält . Dies schließt die \nEwline ein, seddie nach jeder Ersetzung beim Schreiben in stdout eingefügt wird .

Da xargseine mit Backslash- \nEscape versehene Ewline vollständig entfernt wird und die Argumente, die ihr benanntes Dienstprogramm übergibt, auf nicht entkappten Leerzeichen aufgeteilt werden, printfwerden alle satzartigen Zeichenfolgen gedruckt, die xargsEingaben ohne nachfolgende Leerzeichen und in einer einzelnen Zeile pro Zeile einlesen. Was mehr ist - es tut es in Chargen, die sich der ARGMAXGröße nähern - so viele wie möglich gleichzeitig. Und natürlich sedsollte es auch seine Arbeit ziemlich schnell erledigen - es muss nur eine globale Substitution pro Eingabezeile durchgeführt werden.

Die Ergebnisse sehen folgendermaßen aus:

Einige Lorem Ipsum von www.lipsum.com :

sed 's/\([.!?]  *\)\{0,1\}/\1\\/g' <<LIPSUM | xargs printf %s\\n
Section 1.10.32 of "de Finibus Bonorum et Mal
orum", written by Cicero in 45 BC
"Sed ut perspiciatis unde omnis iste natus er
ror sit voluptatem accusantium doloremque lau
dantium, totam rem aperiam, eaque ipsa quae a
b illo inventore veritatis et quasi architect
o beatae vitae dicta sunt explicabo.
Nemo enim ipsam voluptatem quia voluptas sit 
aspernatur aut odit aut fugit, sed quia conse
quuntur magni dolores eos qui ratione volupta
tem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum q
uia dolor sit amet, consectetur, adipisci vel
it, sed quia non numquam eius modi tempora in
cidunt ut labore et dolore magnam aliquam qua
erat voluptatem.
Ut enim ad minima veniam, quis     ...
...
reiciendis voluptatibus maiores alias consequ
atur aut perferendis doloribus asperiores rep
ellat."        1914 translation by H.

LIPSUM

... was druckt ...

Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
Ut enim ad minima veniam, quis     ...
...
reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."        1914 translation by H.

@don_crissti - ja - komisch. Es hat funktioniert w / busybox xargs. Und es tut w / read, aber nicht anders. Es braucht sehr wenig mehr, um es sicherer zu zitieren - ich denke, ich muss. Oder setzen Sie ein tr -d \\nzwischen das sedund xargs. (Ich habe es gerade in der Shell auf meinem Android-Tablet im Badezimmer gemacht, ehrlich)
Mikeserv
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.