Ordina una sezione di un file


8

È possibile ordinare tra due stringhe in un file di grandi dimensioni?

ad esempio, il file corrente è il seguente:

    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

E l'output desiderato è il seguente:

    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

Qui, la sezione HUT 03 VR Controls e HUT 04 Sports Controls è ordinata.

Nel file specificato, le intestazioni di sezione iniziano con caratteri non spaziali mentre il contenuto della sezione inizia sempre con spazio o scheda. Poiché questo file ha più di 100 sezioni, non sarà possibile codificare il nome della sezione in codice / script


Le sezioni su numeri di linea fissa o sono definite da schemi?
Sparhawk,

Le intestazioni di sezione iniziano come primo carattere di linea, mentre il contenuto inizia con spazio / tabulazione. Le sezioni non sono su numeri fissi.
SHW

Vuoi ordinare solo una sezione (come da titolo di domanda e testo) o ogni sezione?
Kusalananda

@Kusalananda Sono d'accordo sul fatto che la domanda sia ambigua su questo punto; l'output di esempio mostra tuttavia tutte le sezioni (o parti di esse) ordinate.
Stephen Kitt,

Non direi che "HUT" usa caratteri esadecimali.
jlliagre,

Risposte:


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 = "")

Questo ordina tutte le sezioni (separatamente), non solo quelle tra due linee specifiche.


Stupendo! Questo è colpo da maestro.
SHW,

6

Per divertirti, ecco un modo per ordinare una singola sezione usando ex:

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%

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

Questo serve awkper aggiungere un numero (e un separatore di tabulazioni) davanti a ciascuna riga corrispondente alla sezione in cui si trova questa linea. Per le intestazioni di sezione, aggiungiamo un numero seguito da un carattere backspace (solo perché il backspace ordina prima delle tabulazioni). Quindi ordiniamo semplicemente i dati risultanti su questi numeri prima di rimuoverli e i separatori di schede aggiunti.

Le intestazioni di sezione vengono rilevate cercando caratteri non vuoti all'inizio della riga.


1
Bello! Mi piace soprattutto il trucco del backspace.
Stephen Kitt,

1
Con questo approccio puoi anche usare il numero di sezione (dopo il HUTcampo) come prefisso, per ordinare anche le sezioni.
Stephen Kitt,

3

Potresti ottenere awke sortcollaborare per portare a termine il lavoro.

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • Installa ogni riga di contenuto in sort
  • Chiamata closesu sortquando si incontra un indicatore di sezione; questo fa sì sortche il suo output venga scaricato sull'output standard ed esca
  • Stampa il marcatore di sezione
  • Una nuova istanza di sortsostituisce le righe di contenuto che seguono il marcatore di sezione
  • Chiama closeil sortalla fine di prendersi cura dei contenuti finali

1

Per tali compiti trovo spesso noioso scrivere una sceneggiatura. Se deve essere fatto solo una volta e forse per alcuni file, può essere fatto abbastanza bene usando una macro se si apre il file vime si digita:

  • GoFAKE SECTION<ESC>: aggiungi una sezione falsa alla fine e assicurati che sia all'inizio della riga (potresti averlo abilitato cindento autoindentabilitato). Ciò è necessario anche per ordinare l'ultima sezione.
  • gg: indietro vai all'inizio del file, quindi il file inizia con una sezione scendi di una riga con j
  • qq: avvia la registrazione di una macro per registrare q
  • v: avvia la selezione
  • /^\S\+<Enter>: cerca l'inizio della sezione successiva
  • k: su una riga
  • :!sort<Enter: ordina la sezione
  • nj: vai al primo elemento della sezione successiva
  • q: interrompe la registrazione della macro
  • @q: ripeti la macro
  • 100@@: ripeti la macro alcune volte (fino a quando non rimangono più sezioni)
  • dd: elimina l'ultima riga del file (il FAKE SECTION)

È possibile che si desideri :set lazyredrawaccelerare l'esecuzione delle macro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.