Wie kann ich zwei Zeilen in einer Datei verbinden, wenn sie beide einem Muster entsprechen?

Wie kann ich zwei Zeilen in einer Datei verbinden, wenn sie beide einem Muster entsprechen?

Ich habe eine Datei mit mehreren Zeilen und möchte die Zeilen verbinden, wenn sie beide einem bestimmten Muster entsprechen.

Ich weiß, dass ich Zeilen finden kann, die zum Muster passen und mit Folgendem zur nächsten Zeile gelangen:

grep -E -A1 'Pattern' filename

Aber wie kann ich überprüfen, ob die nächste Zeile auch dem Muster entspricht und wie gehe ich vor, um die beiden zu verbinden?

Ich habe beispielsweise eine Datei wie diese:

Hello
i
am
John
Smith

Ein Beispielmuster könnte das folgende sein:

'^[A-Z][a-z]+'

In diesem Fall möchte ich die Zeilen also zusammenführen, wenn sie beide mit einem Großbuchstaben beginnen.

Das Ergebnis, das ich erzielen möchte, wäre:

Hello
i
am 
John Smith

Antwort1

/^[A-Z][a-z]+/{
  :a
  N
  /\n[A-Z][a-z]+/{
    s/\n/ /
    b a
  }
}

Speichern Sie es unter join.sedund führen Sie es aus: sed -Ef join.sed file.

Wenn die Zeile mit dem Muster übereinstimmt, starten wir eine Schleife, die die nächste Zeile an den Musterbereich anhängt und das Zeilenumbruchzeichen durch ein Leerzeichen ersetzt, sofern auch diese Zeile mit dem Muster übereinstimmt.

Für GNU Sed können Sie es auf eine Einzeilerform reduzieren:

sed -E '/^[A-Z][a-z]+/{:a;N;/\n[A-Z][a-z]+/{s/\n/ /;b a}}' file

Alternativ kann ein Awk-Skript verwendet werden join.awk, für das das Muster wie folgt angegeben werden sollte p:

{
    if($0~p)c+=1
    else c=0
    printf "%s%s", (c>1 ? " " : ors), $0
    ors=ORS
}
END{print ""}

Ausführen: awk -f join.awk p='^[A-Z][a-z]+' file.

Antwort2

Verwenden Sie sedals Trennzeichen das Nullzeichen ( -z):

$ sed -z 's/\([A-Z][a-z]\+\)\n\([A-Z][a-z]\+\)/\1 \2/'
Hello
i
am
John Smith

Antwort3

Verwenden von Raku (früher bekannt als Perl_6)

raku -e 'given lines.join("\n") { S/ $<first>=[<upper><lower>+] \n $<last>=[<upper><lower>+] /$<first> $<last>/.put};'

Beispieleingabe:

Hello
i
am
John
Smith
goodbye

Beispielausgabe:

Hello
i
am
John Smith
goodbye

Oben sehen Sie eine Lösung, die in Raku, einem Mitglied der Perl-Sprachfamilie, codiert ist. Die Daten werden givenan Raku in der Form gesendet lines, aber da Rakus linesRoutine die Eingabe automatisch verarbeitet, werden die Daten joinmit Zeilenumbrüchen -ed. Das mag zwar ein wenig kompliziert erscheinen, hat aber den Vorteil, dass Rakus linesRoutine die Daten verzögert liest, was bedeutet, dass der obige Codesollte seinspeichereffizient.

Raku implementiert einen S///„nicht-destruktiven“ Operator, der dem bekannten Operator ähnelt (wenn nicht sogar identisch ist) s///(Raku hat diesen auch). Der SOperator „capital-“ hat den Vorteil, dass er"lässt die ursprüngliche Zeichenfolge unverändert und gibt die resultierende Zeichenfolge anstelle von $/ (der Übereinstimmungsvariable) zurück."

Innerhalb der passenden (linken) Hälfte des S///Operatorsbenannte Aufnahmenverwendet. Die Regex-Engine sucht zuerst nach [<upper><lower>+]und weist es dem benannten Capture zu $<first>, dann sucht sie nach einem \n(Newline) und schließlich sucht sie nach einem weiteren [<upper><lower>+], das sie dieses Mal dem benannten Capture zuweist $<last>. Zum Abschluss werden innerhalb der (rechten) Ersetzungshälfte des S///Operators die beiden benannten Captures $<first> $<last>verwendet, um die Übereinstimmung auf der linken Seite zu ersetzen, obwohlmitein Raum undohneder \nZeilenumbruch dazwischen.

Eine alternative Möglichkeit, dasselbe zu erreichen, finden Sie unten. Der Code lässt benannte Captures aus und verwendet stattdessen, <(\n)>um alles aus dem Match-Objekt zu löschen, außer dem, was sich innerhalb der <(…)>Capture-Marker befindet. Dann wird beim Ersetzen \n durch Leerzeichen ersetzt :

raku -e 'put S/ [<upper><lower>+] <(\n)> [<upper><lower>+] / / given lines.join("\n");'  

[Beachten Sie, dass der obige Code nur etwa 4 Zeilen auf 3 Zeilen zusammenfasst George\nHerbert\nWalker\nBush( George Herbert\nWalker\nBush). Wenn Sie alle zeilenweise aufeinanderfolgenden Vorkommen von [<upper><lower>+]in einer Zeile zurückgeben möchten, können Sie diese Frage gerne stellen].

https://docs.raku.org/language/regexes#S///_non-destructive_substitution
https://docs.raku.org/language/regexes#index-entry-regex__Named_captures-Named_captures
https://raku.org

verwandte Informationen