Mesclar linhas duplicadas que possuem os mesmos três primeiros campos

2

Eu tenho a entrada abaixo (mil linhas). Eu quero um comando sed para mesclar linhas duplicadas com os mesmos três primeiros campos que adiciona apenas campos diferentes ou exclui "N / A":

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2

Resultado esperado:

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2
    
por Tony 30.06.2015 / 18:58

3 respostas

3
sed ':n
    s|;N/A;|;|g;$!N
    s|^\(\([^;]*;\)\{3\}\)\(.*\)\n|;|;tn
    P;D
'   <<\IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
LE040A;1;363;(28.5);N/A;SM-1-3
LE040A;1;363;(29.6);N/A;SM-1-4
IN

Isso continuará a ramificar de volta para t est para cada entrada sequencial, mesclando apenas as caudas de cada uma.

Isso é portavelmente escrito, mas é um pouco mais fácil de escrever se você puder usar -E expressões regulares xtended (como você pode com versões BSD ou GNU) ...

sed -E ':n
        s|;N/A;|;|g;$!N
        s|^(([^;]*;){3})(.*)\n|;|;tn
P;D'

Se você queria tudo em uma linha:

sed -Ee:n -e's|;N/A;|;|g;$!N;s|^(([^;]*;){3})(.*)\n|;|;tn' -eP\;D

... funcionaria, mas eu nunca gostei muito de one-liners assim ...

De qualquer forma, a saída do primeiro, é:

OUTPUT

D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);SM-1-1;(27.4);SM-1-2;(28.5);SM-1-3;(29.6);SM-1-4

Para mover também qualquer campo à direita que comece com SM- para a parte final da linha, e para separar cada um com / , acredito que o seguinte deve funcionar:

sed -E ':n
        s|;N/A;|;|g
        s|;(SM-[^;]*)$|/|;$!N
        s|^(([^;]*;){3})(.*)\n|;|;tn
P;D'

Você sabe, a propósito, isso pode ficar muito mais fácil - e muito mais rápido - se você puder ser mais claro e mais específico sobre o que é necessário. Para mim, não parece que você queira mesclar apenas os três primeiros campos idênticos em qualquer duas linhas sequenciais e remover um campo que corresponda a N/A de < em> qualquer linha, e depois mover SM- campos para a cauda de qualquer linha. Pelo contrário, para mim, parece que todos esses trabalhos individuais que você nomeia são, na verdade, um e o mesmo, e que você realmente quer algo como:

  • Se uma linha de entrada for encontrada com três campos alfanuméricos delimitados por ponto-e-vírgula, um campo flutuante entre parênteses seguido por outro delimitador de dois pontos, um campo N/A , devemos fazer o seguinte:
    1. Verifique se a próxima linha também corresponde a essa descrição e, portanto, compare os três primeiros campos da linha atual e da próxima.
    2. Se uma correspondência for encontrada, retenha apenas o último campo da próxima linha e, em seguida, recrute para tentar novamente.
    3. Independentemente, sempre remova o campo que corresponde a N/A e substitua o último ; por / .
  • Independentemente disso, imprima tudo o que resta para stdout.

Você vê como isso difere? É uma série de tarefas executadas que dependem de uma única condição inicial. Se você puder ser tão claro, suas correspondências não terão que compensar sua generalidade no tempo de processamento.

Se eu estiver correto, o seguinte poderia funcionar:

sed '   \|;N/A;|!b
        s||/|;$!N
        \|^\(.*(\)\(.*)\)\(.*\)\(\n\)\(.*)\)|!P
        s||;(|;D
' <<\IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);N/A;SM-1-1
LE040A;1;363;(27.4);N/A;SM-1-2
LE040A;1;363;(28.5);N/A;SM-1-3
LE040A;1;363;(29.6);N/A;SM-1-4
IN
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);(28.5);(29.6)/SM-1-1/SM-1-2/SM-1-3/SM-1-4

... Aqui está -E em uma linha ...

sed -e'\|;N/A;|!b' -e's||/|;$!N;\|^\(.*(\)\(.*)\)\(.*\)\(\n\)\(.*)\)|!P;s||;(|;D'

... ou em -E sintaxe xtended ...

sed -Ee'\|;N/A;|!b' -e's||/|;$!N;\|^(.*\()(.*\))(.*)(\n)(.*\))|!P;s||(|;D'
    
por 30.06.2015 / 20:11
1

TXR:

@(repeat)
@  (cases)
@id;@f2;@f3;@val1;@nil;@sm1
@id;@f2;@f3;@val2;@nil;@sm2
@    (do (put-line '@id;@f2;@f3;@val1;@val2;@sm1/@sm2'))
@  (or)
@line
@    (do (put-line line))
@  (end)
@(end)

$ txr data.txr data
D04005;4;279;0;0;SSM-4-1
D04005;5;40;0;0;SSM-5-1
LE040A;1;363;(26.3);(27.4);SM-1-1/SM-1-2
    
por 30.06.2015 / 21:30
1
sed -r ':a;N;s!;N/A!!g;s/^(([^;]*;){3})(.*)\n/;/;T;s!^(([^S][^;]*;){3,})(S*SM-[^;]*);(([^S][^;]*;){1,})(.*)!/!;ta' inputfile

Mesmo que a matemática implícita do seu comentário para apenas 6 campos na saída sugira que haja apenas pares, esta é a versão em loop com alterações na saída SM-1-1 / SM-1-2 quando correspondida.

    
por 01.07.2015 / 00:35