Ich habe eine lange Textdatei (eine Tab-Datei für den Stardict-Editor), die aus Zeilen im folgenden Format besteht:
word1 some text
word1 some other text
word2 more text
word3 even more
und möchte es umwandeln
word1 some text<br>some other text
word2 more text
word3 even more
Dies bedeutet, dass nachfolgende Zeilen (die Datei ist sortiert), die mit demselben Wort beginnen, zu einer einzigen zusammengeführt werden sollten (hier werden die Definitionen durch getrennt <br>
). Linien mit gleichem Anfang können auch häufiger als nur zweimal erscheinen. Das Zeichen, das Wort und Definition trennt, ist ein Tabulatorzeichen und in jeder Zeile eindeutig. word1
, word2
, word3
Sind natürlich Platzhalter für etwas willkürlich (außer Tab und Zeilenumbrüchen) , die ich weiß nicht im Voraus.
Ich kann mir einen längeren Perl-Code vorstellen, der dies tut, aber ich frage mich, ob es in Perl eine kurze Lösung oder etwas für die Befehlszeile gibt. Irgendwelche Ideen?
quelle
(Es dauert 2 Sekunden, um ein Wörterbuch mit 23 MB und 1,5 Zeilen in meinem 6 Jahre alten Laptop zu verarbeiten.)
quelle
Mit
sed
:(Hinweis: Bei vielen
sed
s ist das obige\t
Escape ungültig und<tab>
an seiner Stelle sollte ein wörtliches Zeichen verwendet werden.)Und wenn Sie GNU haben
sed
, können Sie es etwas einfacher schreiben:Es funktioniert, indem die Eingabe beim Lesen schrittweise gestapelt wird. Wenn zwei aufeinanderfolgende Zeilen nicht mit derselben Nicht-Leerzeichenfolge beginnen, wird die erste davon
P
gedruckt. Andernfalls wird die dazwischenliegende neue Zeile an den Kopf der Zeile verschoben und die unmittelbar darauf folgende übereinstimmende Zeichenfolge (einschließlich der Registerkarte) durch die Zeichenfolge ersetzt<br>
.Beachten Sie, dass die Stapel hier verwendete Methode könnte Auswirkungen auf die Leistung haben , wenn die Linie , dass
sed
zusammenbaut sehr lange wächst. Wenn es länger als 8 KB wächst, überschreitet es die von POSIX angegebene Mindestgröße des Musterspeicherpuffers.Unabhängig davon, welche der beiden Möglichkeiten aufgetreten ist, wird als letztes
sed
D
bis zum ersten vorkommenden\n
Ewline-Zeichen im Musterraum eletiert und beginnt mit dem, was übrig bleibt. Wenn also zwei aufeinanderfolgende Zeilen nicht mit identischen Zeichenfolgen beginnen, wird die erste gedruckt und gelöscht, andernfalls wird die Ersetzung durchgeführt und dasD
elete löscht nur die\n
ewline, die sie zuvor getrennt hat.Und so druckt der obige Befehl:
Ich habe oben eine
<<\HERE_DOC
Eingabe verwendet, aber Sie sollten wahrscheinlich alles von<<\IN
on ablegen und</path/to/infile
stattdessen verwenden.quelle
-E
Option zu GNUsed
ist eine undokumentierte Alternative zur Verwendung-r
, mit der Ausnahme, dass 1. sie sinnvoller ist (was sollte eigentlich-r
jemals bedeuten?) , 2. Sie funktioniert auch in BSDsed
, 3. POSIX hat eine geplante Änderung, die angewendet werden soll die nächste Version der Spezifikation, die offiziell-E
als die richtige Syntax segnet , um erweiterte reguläre Ausdrücke in a zu ermöglichensed
.Dies ist in der Tat Standard für
awk
. Hier ist eine knappe Lösung, die die Betriebsdaten nicht ändert:quelle
FS
Definition!$0
(das das TAB enthält) zuout
.LC_ALL=en_US.UTF-8
.) Andernfalls wäre es hilfreich, einige der Beispielzeilen zu erhalten, in denen Probleme auftreten. Es kann auch sein, dass das Datenformat nicht überall so ist, wie Sie es erwartet haben. Ihr Feedback wird geschätzt, um zu verfolgen, wo in der Verarbeitungskette das Problem liegt. Irgendwo wird ein Fix notwendig sein.In Python:
Dies erwartet das Trennzeichen (
<br>
) als erstes Argument für das Programm und den Dateinamen als zweites Argumentquelle
Versuchen
die mit Ihrer Eingabe geben
tha awk merke dir im Grunde das erste Wort in der vorherigen Zeile und drucke keine neue Zeile.
quelle