Divide o arquivo de entrada com quebras de linha

4

Estou tentando inserir quebras de linha em um arquivo com base nos mesmos nomes que, por acaso, são o segundo campo do meu arquivo. Então, meu arquivo de entrada é como abaixo.

17412193|name1|organization
43979400|name1|organization
1405541|name2|organization
53595498|name2|organization
50439202|name2|organization
54678379|name3|Not Found
21757330|name3|organization

Então, estou tentando obter a saída como

17412193|name1|organization
43979400|name1|organization
###linebreak inserted here
1405541|name2|organization
53595498|name2|organization
50439202|name2|organization
###linebreak inserted here
54678379|name3|Not Found
21757330|name3|organization
###linebreak inserted here

Estou usando essa quebra de linha para dividir o arquivo de entrada para agrupar os nomes semelhantes. Mais tarde eu aplicaria um algoritmo de similaridade nesses nomes agrupados. Então, para o exemplo acima, após a saída eu aplicaria o algoritmo de similaridade em 3 pares de nomes.

    
por Ramesh 26.03.2014 / 16:43

4 respostas

8

Assumindo que seu arquivo seja classificado / agrupado pelo 2º campo já

awk -F '|' 'NR>1 && $2 != prev {print ""} {prev=$2; print}' file
    
por 26.03.2014 / 16:46
4

Aqui está uma solução de Perl insensível a maiúsculas e minúsculas:

perl -F'\|' -lape 'unless($F[1]=~/^$pre$/i || $.==1){print ""}; $pre=$F[1]' file 

Explicação:

  • O -a divide as linhas de entrada na matriz @F , fazendo o perl agir como awk.
  • O -F é o separador de campos
  • -p significa imprimir cada linha de entrada
  • -l adiciona \n a cada chamada de impressão, por isso print "" imprime uma nova linha.
  • unless($F[1]=~/^$pre$/i || $.==1) : a menos que o segundo campo seja o mesmo da linha anterior (o i em //i torna a correspondência insensitiva) ou a menos que seja a primeira linha.
  • $pre=$F[1] : salve este segundo campo de linhas como $pre .

@GlennJackman sugeriu uma versão ligeiramente diferente nos comentários, que provavelmente será mais rápida para arquivos maiores:

perl -F'\|' -lape 'unless(lc($F[1]) eq lc($pre) || $.==1){print ""}; $pre=$F[1]' file 
    
por 26.03.2014 / 17:03
4

Uma solução Perl mais curta:

perl -pe 'print "\n" if ($l =~ /name\d+/ && $_ !~ /$&/);$l=$_;' input
  • se a última linha ( $l ) foi name\d+ e a linha atual não corresponde à última, depois imprima nova linha
  • atribua linha atual a $l

Uma solução mais geral

perl -pe 'print "\n" if ($l =~ /\|([^\|]+)/ && $_ !~ /$1/);$l=$_;'  input
    
por 26.03.2014 / 18:41
0
#!/bin/sh
#shell basics, POSIX compliant
(set -f ;IFS='|
' ; set -- $(cat) ; while [ -n "$3" ] ;do {
[ "${t=$2}" != "$2" ] && echo && t=$2
printf '%s|%s|%s\n' "$1" "$2" "$3" ; shift 3 
} ; done )<<\SAMPLE
17412193|name1|organization 
43979400|name1|organization 
1405541|name2|organization 
53595498|name2|organization 
50439202|name2|organization 
54678379|name3|Not Found 
21757330|name3|organization
SAMPLE

Output

17412193|name1|organization 
43979400|name1|organization 

1405541|name2|organization 
53595498|name2|organization 
50439202|name2|organization 

54678379|name3|Not Found 
21757330|name3|organization
    
por 27.03.2014 / 12:52