Sortieren Sie einen Abschnitt einer Datei

8

Ist es möglich, zwischen zwei Zeichenfolgen in einer großen Datei zu sortieren?

zB Aktuelle Datei ist wie folgt:

    0cf  Front Brake
    0d0  Rear Brake
    0ce  Handle Bars
HUT 03  VR Controls
    009  Vest
    001  Belt
    002  Body Suit
    020  Stereo Enable
    003  Flexor
    007  Hand Tracker
    004  Glove
    006  Head Mounted Display
    008  Oculometer
    00a  Animatronic Device
    000  Unidentified
    021  Display Enable
    005  Head Tracker
HUT 04  Sport Controls
    000  Unidentified
    002  Golf Club
    001  Baseball Bat

Und die gewünschte Ausgabe ist wie folgt:

    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Hier wird der Abschnitt HUT 03 VR Controls und HUT 04 Sports Controls aussortiert.

In einer bestimmten Datei beginnen Abschnittsüberschriften mit Nicht-Leerzeichen, während Abschnittsinhalte immer mit Leerzeichen oder Tabulatoren beginnen. Da diese Datei mehr als 100 Abschnitte enthält, ist es nicht möglich, den Abschnittsnamen in Skript / Befehl fest zu codieren

SHW
quelle
Sind die Abschnitte auf Festnetznummern oder durch Muster definiert?
Sparhawk
Abschnittsüberschriften beginnen als erstes Zeichen der Zeile, während der Inhalt mit Leerzeichen / Tabulatoren beginnt. Abschnitte sind nicht auf festen Nummern.
SHW
Möchten Sie nur einen Abschnitt (gemäß Titel der Frage und des Textes) oder jeden Abschnitt sortieren ?
Kusalananda
@Kusalananda Ich stimme zu, dass die Frage in diesem Punkt nicht eindeutig ist. Die Beispielausgabe zeigt jedoch alle Abschnitte (oder Teile davon), die sortiert werden.
Stephen Kitt
Ich würde nicht sagen, dass "HUT" Hex-Zeichen verwendet.
Jlliagre

Antworten:

7

In Python:

#!/usr/bin/python3

with open("file.txt", "r") as ins:
    lines = []
    for line in ins:
        if line.startswith((" ", "\t")):
            lines.append(line)
        else:
            lines.sort()
            print(*lines, end = "", sep = "")
            print(line, end = "")
            lines = []
    lines.sort()
    print(*lines, end = "", sep = "")

Dadurch werden alle Abschnitte (separat) sortiert, nicht nur die zwischen zwei bestimmten Zeilen.

Stephen Kitt
quelle
Hervorragend! Das ist Meisterstück.
SHW
6

Zum Spaß gibt es hier eine Möglichkeit, einen einzelnen Abschnitt folgendermaßen zu sortieren ex:

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%
jlliagre
quelle
6
$ awk 'BEGIN { OFS="\t"; s=0 } /^[^[:blank:]]/ { print ++s "\b", $0; next } { print s, $0 }' file | sort -n | cut -f 2-
    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Hiermit wird awkvor jeder Zeile eine Zahl (und ein Tabulatortrennzeichen) eingefügt, die dem Abschnitt entspricht, in dem sich diese Zeile befindet. Bei Abschnittsüberschriften fügen wir eine Zahl gefolgt von einem Rücktastezeichen hinzu (nur weil die Rücktaste vor Tabulatoren sortiert wird). Dann sortieren wir einfach die resultierenden Daten nach diesen Zahlen, bevor wir sie und die hinzugefügten Tabulatortrennzeichen entfernen.

Abschnittsüberschriften werden erkannt, indem am Anfang der Zeile nach nicht leeren Zeichen gesucht wird.

Kusalananda
quelle
1
Nett! Besonders gut gefällt mir der Backspace-Trick.
Stephen Kitt
1
Bei diesem Ansatz können Sie auch die Abschnittsnummer (nach dem HUTFeld) als Präfix verwenden, um die Abschnitte ebenfalls zu sortieren.
Stephen Kitt
3

Sie könnten bekommen awkund sortzusammenarbeiten, um die Arbeit zu erledigen.

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • Leiten Sie jede Inhaltszeile in sort
  • Rufen Sie closean, sortwenn eine Abschnittsmarkierung gefunden wird. Dies führt sortdazu, dass die Ausgabe auf die Standardausgabe gespült und beendet wird
  • Drucken Sie die Abschnittsmarkierung
  • Eine neue Instanz von sortübernimmt für die Inhaltszeilen nach der Abschnittsmarkierung
  • Rufen Sie closeam sortEnde an, um sich um nachfolgende Inhalte zu kümmern
iruvar
quelle
1

Für solche Aufgaben finde ich es oft mühsam, ein Skript zu schreiben. Wenn es nur einmal und möglicherweise für einige Dateien ausgeführt werden muss, kann es ganz gut mit einem Makro ausgeführt werden, wenn Sie die Datei öffnen vimund Folgendes eingeben:

  • GoFAKE SECTION<ESC>: Fügen Sie am Ende einen gefälschten Abschnitt hinzu und stellen Sie sicher, dass dieser am Anfang der Zeile steht (möglicherweise vorhanden cindentoder autoindentaktiviert). Dies ist auch zum Sortieren des letzten Abschnitts erforderlich.
  • gg: Zurück zum Anfang der Datei, dann beginnt die Datei mit einem Abschnitt, der eine Zeile nach unten geht j
  • qq: Starten Sie die Aufnahme eines Makros, um q zu registrieren
  • v: Auswahl starten
  • /^\S\+<Enter>: Suche nach dem Anfang des nächsten Abschnitts
  • k: eine Zeile nach oben
  • :!sort<Enter: sortiere den Abschnitt
  • nj: Gehen Sie zum ersten Element des nächsten Abschnitts
  • q: Beenden Sie die Aufnahme des Makros
  • @q: Wiederholen Sie das Makro
  • 100@@: Wiederholen Sie das Makro einige Male (bis keine Abschnitte mehr übrig sind)
  • dd: lösche die letzte Zeile der Datei (die FAKE SECTION)

Möglicherweise möchten Sie die Makroausführung :set lazyredrawbeschleunigen.

MarcDefiant
quelle