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.sed
und 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 sed
als 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 given
an Raku in der Form gesendet lines
, aber da Rakus lines
Routine die Eingabe automatisch verarbeitet, werden die Daten join
mit Zeilenumbrüchen -ed. Das mag zwar ein wenig kompliziert erscheinen, hat aber den Vorteil, dass Rakus lines
Routine 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 S
Operator „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 \n
Zeilenumbruch 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