Classificar uma seção de um arquivo

8

É possível classificar entre duas strings em um arquivo grande?

por exemplo, o arquivo atual é como:

    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 a saída desejada é a seguinte:

    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

Aqui, a seção HUT 03 VR Controls e HUT 04 Sports Controls é classificada.

Em um determinado arquivo, os cabeçalhos da seção começam com caracteres que não são espaços, enquanto o conteúdo da seção sempre começa com espaço ou tabulação. Como esse arquivo tem mais de 100 seções, não será possível codificar o nome da seção no script / comando

SHW
fonte
As seções estão em números de linhas fixas ou definidas por padrões?
Sparhawk
Os cabeçalhos da seção começam como o primeiro caractere da linha, enquanto o conteúdo começa com espaço / guia. As seções não estão em números fixos.
SHW
Você deseja classificar apenas uma seção (conforme o título da pergunta e o texto) ou todas as seções?
Kusalananda
@Kusalananda Concordo que a questão é ambígua nesse ponto; o exemplo de saída, no entanto, mostra todas as seções (ou partes delas) sendo classificadas.
Stephen Kitt
Eu não diria que "HUT" usa caracteres hexadecimais.
Jlliagre 16/05/19

Respostas:

7

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

Isso classifica todas as seções (separadamente), não apenas aquelas entre duas linhas específicas.

Stephen Kitt
fonte
Soberbo! Isso é golpe de mestre.
SHW
6

Para se divertir, aqui está uma maneira de classificar uma única seção usando ex:

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%
jlliagre
fonte
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

Isso usa awkpara adicionar um número (e um separador de tabulação) na frente de cada linha correspondente à seção em que esta linha está. Para os cabeçalhos das seções, adicionamos um número seguido de um caractere de backspace (apenas porque o backspace é classificado antes das guias). Em seguida, simplesmente classificamos os dados resultantes nesses números antes de removê-los e os separadores de tabulação adicionados.

Os cabeçalhos das seções são detectados procurando caracteres não em branco no início da linha.

Kusalananda
fonte
11
Agradável! Eu gosto especialmente do truque de backspace.
Stephen Kitt
11
Com essa abordagem, você também pode usar o número da seção (após o HUTcampo) como prefixo, para classificar as seções também.
Stephen Kitt
3

Você pode obter awke sortcooperar para fazer o trabalho.

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • Canalize cada linha de conteúdo sort
  • Chamada closeem sortquando um marcador de seção é encontrado; isso faz sortcom que libere sua saída para saída e saída padrão
  • Imprimir o marcador de seção
  • Uma nova instância de sortcontrole para as linhas de conteúdo após o marcador de seção
  • Ligue closeno sortfinal para cuidar do conteúdo à direita
iruvar
fonte
1

Para tais tarefas, muitas vezes acho entediante escrever um script. Se ele precisar ser feito apenas uma vez e talvez com alguns arquivos, poderá ser feito com bastante bom gosto usando uma macro se você abrir o arquivo vime digitar:

  • GoFAKE SECTION<ESC>: adicione uma seção falsa no final e verifique se está no início da linha (você pode ter cindentou autoindenthabilitado). Isso é necessário para classificar a última seção também.
  • gg: voltar, vá para o início do arquivo e, em seguida, o arquivo começa com uma seção, desça uma linha com j
  • qq: começa a gravar uma macro para registrar q
  • v: inicia seleção
  • /^\S\+<Enter>: procure o início da próxima seção
  • k: até uma linha
  • :!sort<Enter: classifica a seção
  • nj: vá para o primeiro elemento da próxima seção
  • q: parar de gravar a macro
  • @q: repita a macro
  • 100@@: repita a macro algumas vezes (até não sobrarem seções)
  • dd: exclua a última linha do arquivo (the FAKE SECTION)

Convém :set lazyredrawacelerar a execução da macro.

MarcDefiant
fonte