Classificação agrupada de parágrafos contínuos (separados por linha em branco)?

8

Eu acho que sou bastante experiente agora na classificação por colunas ; no entanto, não encontrei nada até agora como classificar linhas contínuas .

Supondo que temos um arquivo de texto que se parece com isso: (muito simplificado, é claro)

Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

Agora, é possível classificar as linhas alfanumericamente por cada bloco separadamente ? Quero dizer, para que o resultado seja assim:

Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel

Contando o que encontrei na página sort man, isso pode não ser possível com o comando interno UNIX sort . Ou pode mesmo ser feito sem ter que recorrer a ferramentas externas / de terceiros?

    
por syntaxerror 14.08.2013 / 19:11

5 respostas

9

A solução awk do Drav é boa, mas isso significa executar um comando sort por parágrafo. Para evitar isso, você poderia fazer:

< file awk -v n=0 '!NF{n++};{print n,$0}' | sort -k1n -k2 | cut -d' ' -f2-

Ou você pode fazer tudo em perl :

perl -ne 'if (/\S/){push@l,$_}else{print sort@l if@l;@l=();print}
          END{print sort @l if @l}' < file

Observe que, acima, os separadores são linhas em branco (para awk one, linhas com apenas espaço ou caracteres de tabulação, para perl one, qualquer caractere de espaçamento horizontal ou vertical) em vez de linhas vazias. Se você quiser linhas vazias, poderá substituir !NF por !length ou $0=="" e /\S/ por /./ .

    
por 14.08.2013 / 22:21
8
awk -v RS= -v cmd=sort '{print | cmd; close(cmd); print ""}' file

Definir o separador de registro RS como uma string vazia faz o awk entrar em parágrafos de cada vez. Para cada parágrafo, canalize o parágrafo (em $0 ) para cmd (que está definido como sort ) e imprima a saída. Imprima uma linha em branco para separar os parágrafos de saída com um print "" .

Se estamos dando exemplos de perl, então eu apresento uma abordagem alternativa que a de Stephane:

perl -e 'undef $/; print join "\n", sort (split /\n/), "\n" 
    foreach(split(/\n\n/, <>))' < file

Desmarque o separador de campo ( undef $/ ), isso nos permite usar <> e obter todo o STDIN. Nós então split que cerca de \n\n (parágrafos). foreach "paragraph", sort as linhas por split em torno de novas linhas, sort ing e, em seguida, join juntando-as novamente e adicionando uma \n .

No entanto, isso tem um efeito colateral de adicionar um separador "parágrafo à direita" no último parágrafo (se não tiver um antes). Você pode contornar isso com um pouco menos bonita:

perl -e 'undef $/; print join "\n", sort (split /\n/) , (\$_ == \$list[-1] ? "" : "\n")
    foreach(@list = split(/\n\n/, <>))' < file

Isso atribui os parágrafos a @list e, em seguida, há uma "operação ternária" para verificar se é o último elemento do foreach (a \$_ == \$list[-1] check). imprima "" se for ( ? ... ), senão ( : ... ) imprima "\n" para todos os outros "parágrafos" (elementos de @list ).

    
por 14.08.2013 / 20:03
5

Eu escrevi uma ferramenta no haskell que permite usar o comando sort, shuf, tac ou qualquer outro comando em parágrafos de texto.

link
EDIT: a ferramenta também está incluída neste repo: link

Ele divide o texto em blocos, une os subblocos com %code% char, canaliza o comando e finalmente faz a mesma coisa ao contrário.

28-08-2015 : Eu encontrei outro uso pessoal para esta ferramenta - selecionando N parágrafos depois de uma linha.

paramap grep -aA2 '^reddit usernames' < ~/my-username-file
reddit usernames

foo
bar
baz

a couple
more of these
    
por 29.06.2015 / 00:38
4

Se você tem o GNU awk disponível, você pode classificar cada bloco usando a função asort() integrada. Algo assim:

blocksort.awk

function sort_n_print(array) {
  asort(array)
  for(i=1; i<=length(array); i++)
    print array[i]
  delete array
}

NF { a[++x] = $0 }

!NF { sort_n_print(a); print }

END { sort_n_print(a) }

Execute assim:

awk -f blocksort.awk infile
    
por 15.08.2013 / 11:08
1

TXR Lisp passo a passo:

$ cat data
Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

$ txr -p '(get-lines)' < data
("Echo" "Alpha" "Delta" "Charlie" "" "Golf" "Bravo" "Hotel" "Foxtrot")

$ txr -t '(get-lines)' < data
Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

$ txr -p '(partition* (get-lines) (op where [chain length zerop]))' < data
(("Echo" "Alpha" "Delta" "Charlie") ("Golf" "Bravo" "Hotel" "Foxtrot"))

$ txr -p '[mapcar sort (partition* (get-lines) (op where [chain length zerop]))]' < data
(("Alpha" "Charlie" "Delta" "Echo") ("Bravo" "Foxtrot" "Golf" "Hotel"))

$ txr -p '(interpose (list "") [mapcar sort (partition* (get-lines) (op where [chain length zerop]))])' < data
(("Alpha" "Charlie" "Delta" "Echo") ("") ("Bravo" "Foxtrot" "Golf" "Hotel"))

$ txr -t '(interpose (list "") [mapcar sort (partition* (get-lines) (op where [chain length zerop]))])' < data
Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel

Referências: linhas de pesquisa , partition* , op , onde , cadeia , comprimento , zerop , mapcar , interpor .

    
por 29.06.2015 / 08:02