como imprimir a coluna mais próxima ao procurar por strings específicas

2

Eu tenho um arquivo com cerca de 12 000 linhas.

pk=91001011964;fck=85;fcv=true;fpi=1;fci=cacf;fmd=1422745568,;fck=83;fcv=decoccm;fpi=1;fci=cacf;fmd=1423070648,;fck=87;fcv=false;fpi=1;fci=cacf;fmd=1422745568,;fck=86;fcv=true;fpi=1;fci=cacf;fmd=1422745568,;fck=35;fcv=54bed48ad84397433fef0a350d65a893;fpi=1;fci=cacf;fmd=1422745568,;fck=83;fcv=travide;fpi=1;fci=cacf;fmd=1422811693,;fck=88;fcv=true;fpi=1;fci=cacf;fmd=1422745568,;fck=84;fcv=10;fpi=1;fci=cacf;fmd=1422745568;vpi=ppi=1;pci=cacf;pmd=1423070648;pos=null;pod=0;pso=null;psd=0;vos=null
pk=91001045537;fck=86;fcv=true;fpi=1;fci=cacf;fmd=1421428238,;fck=85;fcv=true;fpi=1;fci=cacf;fmd=1421428238,;fck=87;fcv=false;fpi=1;fci=cacf;fmd=1421428238,;fck=88;fcv=true;fpi=1;fci=cacf;fmd=1421428238,;fck=84;fcv=10;fpi=1;fci=cacf;fmd=1421428238,;fck=35;fcv=cd9b9ed4fc167d8007dd9544114bc83f;fpi=1;fci=cacf;fmd=1421428238,;fck=83;fcv=demelog;fpi=1;fci=cacf;fmd=1421557377;vpi=ppi=1;pci=cacf;pmd=1421557377;pos=null;pod=0;pso=null;psd=0;vos=null   
pk=91001440737;fck=86;fcv=true;fpi=1;fci=cacf;fmd=1421687966,;fck=85;fcv=true;fpi=1;fci=cacf;fmd=1421687966,;fck=87;fcv=true;fpi=1;fci=cacf;fmd=1421687966,;fck=88;fcv=true;fpi=1;fci=cacf;fmd=1421687966,;fck=84;fcv=10;fpi=1;fci=cacf;fmd=1421687966,;fck=35;fcv=7360072ca14cb5d5578a3902fbe51792;fpi=1;fci=cacf;fmd=1421687191;fck=78;fcv=de724a544277d79c14d19809fe51ab71;fpi=1;fci=cacf;fmd=1421687966,;fck=83;fcv=demelog;fpi=1;fci=cacf;fmd=1421816564;vpi=ppi=1;pci=cacf;pmd=1421816564;pos=null;pod=0;pso=null;psd=0;vos=null

Eu preciso analisar o arquivo, procurar por valores de string específicos em uma ordem específica na linha e imprimir ou escolher a coluna mais próxima para essa linha. Se esse valor de sequência não existir, imprima uma coluna vazia.

Digamos que eu tenha fck=35 . se existir, imprima a string pesquisada e o fmd mais próximo. Para a linha 3, seria fck=35;fmd=1421687191 . Se fck=35 não existir, adicione uma coluna vazia e isso tornaria fck=35;;

Digamos que estou cuidando do fck=78 . Se existir, imprima a string pesquisada e o fmd mais próximo. Para a linha 3, terei fck=78;fmd=1421687966 . Se fck=78 não existir, adicione uma coluna vazia e isso tornará fck=78;; .

As outras condições são as seguintes

For fck=84 look for the next fcv For fck=85 look for the next fcv For fck=86 look for the next fcv For fck=83 look for the next fcv O próximo fcv para fck = 83 pode ser naismc, decoide, decoccm, travide, travccm ou mariccm

Vou usar a linha 3 como meu exemplo:

fck=35;fmd=1421687191;fck=78;fmd=1421687966;fck=84;fcv=10;fck=85;fcv=true;fck=86;fcv=true;fck=83;fcv=demelog

ou (no caso de fmd ou fcv estão faltando ou pelo menos alguns: esta parte não é mais a linha 3, apenas outra linha que eu não coloquei no meu exemplo, mas eu acho que não importa)

fck=35;;fck=78;;fck=84;fcv=10;fck=85;fcv=true;fck=86;;fck=83;fcv=demelog

Eu estava pensando em fazer isso em awk ou sed . Mas eu tenho uma dúvida sobre o quão poderoso é e para o que tenho visto até agora, não é útil. Talvez o Python possa fazer o truque, mas eu não estou familiarizado com o Python.

Qualquer ajuda é bem-vinda.

Um companheiro meu me ajudou com isso

awk -F\; -v fck=78 '{for (i=1;i<=NF;i++) if($i=="fck="fck) print "fck="fck";"$(i-1)}' name_of_the_file

Como você pode ver, é apenas uma condição, aqui fck = 78, quando eu preciso ter todas as condições acima.

Qualquer dica sobre o que eu posso melhorar nesse pequeno script ou qualquer coisa que possa fazer a diferença seria ótimo. Mas outro roteiro é possível. Eu estava pensando em Python, mas não tenho certeza de como fazer isso.

TIA

    
por Andy K 10.02.2015 / 15:13

2 respostas

1

Eu suponho que você tenha um arquivo com as várias strings que você está procurando. Algo parecido com isto:

fck=35 fmd
fck=78 fcv
bnv=12 fcv

Para cada um desses, você deseja pesquisar o arquivo e, se uma linha corresponder a qualquer um dos padrões, você deseja o primeiro valor fmd após a string correspondente. Se assim for, eu faria isso em perl da seguinte forma:

#!/usr/bin/env perl

## Open the list of search patterns.
## The script expects it to be the 1st argument.
open(my $list,"$ARGV[0]");
## Read the file and save the patterns
## in the %pat hash.
while (<$list>) {
    ## remove trailing newlines
    chomp;
    ## separate the search pattern from the target
    my @fields=split(/\s+/);

    ## Save the search pattern and accompanying target in
    ## in the hash (%pats). 
    $pats{$fields[0]}=$fields[1];
}

## Open the list of search patterns.
## The script expects it to be the 2nd argument.
open(my $file,"$ARGV[1]");

## Read the file
while (<$file>) {
    ## split the line on ';' into the @fields array
    my @fields=split(/;/);

    ## This is the string that will be printed for
    ## the current line.
    my $outstring="";
    ## Check each of the search patterns against
    ## each of the fields.
    foreach my $pat(keys(%pats)) {
        ## Add the pattern to the outstring
        $outstring.="$pat;";
        ## save all all 1st fmd values that follow
        ## this pattern. 
        my @matches= ( /$pat.+?($pats{$pat}=[^;]+)/g );
        ## Add this pattern's matches to the output string.
        $outstring.= join(";",@matches) . ";";
    }
    ## Print the output string for this line
    print "$outstring\n";
}

Se você salvar o script acima como, por exemplo, parser.pl no seu $PATH e torná-lo executável ( chmod 755 ~/bin/parser.pl ), poderá executá-lo da seguinte forma:

$ parser.pl list.txt file.txt 
bnv=12;;fck=35;fmd=1422745568,;fck=78;;
bnv=12;;fck=35;fmd=1421428238,;fck=78;;
bnv=12;;fck=35;fmd=1421687191 fmd=1111111111;fck=78;fcv=de724a544277d79c14d19809fe51ab71;
    
por 10.02.2015 / 16:18
0

Se você está procurando a coluna mais próxima e conhece o delimitador, isso deve ser uma tarefa fácil para o grep e sed.

grep -e "fck=35" 

Retornará toda a linha fck = 35 está ativada. Em seguida, canalize-o para dois seds para obter o que deseja.

grep -e "fck=35" | sed s/.*fck=35;//g | sed s/;.*//g

o primeiro sed substitui tudo antes de fck = 35; e fck = 35; se sem nada (remove), o segundo sed remove tudo após o próximo delimitador.

Mas parece que você também quer poder selecionar uma coluna específica (fmd) na linha, para isso você precisa de algo mais como:

grep -e "fck=35" | sed s/.*fmd=/fmd=/g | sed s/[;,].*//g

Isso remove todos os elementos antes de 'fmd =' e, em seguida, remove tudo após o próximo delimitador (ou vírgula, parece que você precisa lidar com isso).

    
por 10.02.2015 / 16:27