Remove tudo entre a segunda e a segunda ocorrência do jogo

4

Eu tenho uma string que gostaria de formatar. Gostaria de remover tudo entre o segundo ; e o segundo último ; .

Entrada

cellular organisms;Eukaryota;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;  

Saída

cellular organisms;Eukaryota;Tribolium castaneum;

Eu tentei usar sed

sed 's/;[^;]*//' <<<"cellular organisms;Eukaryota;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;"

produz

cellular organisms;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;
    
por Mitul Patel 22.03.2015 / 15:58

6 respostas

5

Você pode fazer isso facilmente com awk :

awk -F\; '{print $1 ";" $2 ";" $(NF-1) ";" $NF}'

Isso divide a entrada usando ; ( -F\; ) e imprime o primeiro ( $1 ), o segundo ( $2 ), o penúltimo e o último campo ( $(NF-1) e $NF ; NF contém o número de campos).

A seguinte variante reutiliza o separador de campos especificado na saída:

awk -F\; '{print $1 FS $2 FS $(NF-1) FS $NF}'

Janis sugeriu uma versão melhorada usando OFS também:

awk 'BEGIN{FS=OFS=";"} {print $1,$2,$(NF-1),$NF}'

ou, se você quiser manter o separador como outro parâmetro:

awk -F\; 'BEGIN{OFS=FS} {print $1,$2,$(NF-1),$NF}'
    
por 22.03.2015 / 16:24
3

Algumas aproximações de Perl. Em todos os casos, executei este comando para preencher $string :

string="cellular organisms;Eukaryota;Opisthokonta;Metazoa;Eumetazoa;Bilateria;Protostomia;Ecdysozoa;Panarthropoda;Arthropoda;Mandibulata;Pancrustacea;Hexapoda;Insecta;Dicondylia;Pterygota;Neoptera;Endopterygota;Coleoptera;Polyphaga;Cucujiformia;Tenebrionoidea;Tenebrionidae;Tenebrionidae incertae sedis;Tribolium;Tribolium castaneum;"

$ perl -F';' -lane '$"=";"; print "@F[0,1,$#F-1];"' file 
cellular organisms;Eukaryota;Tribolium castaneum;

ou

$ perl -F';' -lane 'print "$F[0];$F[1];$F[$#F];"' <<<"$string"
cellular organisms;Eukaryota;Tribolium castaneum;

ou

$ perl -F';' -lane 'print join(";", @F[0,1,$#F-1]) . ";"' <<<"$string"
cellular organisms;Eukaryota;Tribolium castaneum;
    
por 22.03.2015 / 17:35
3

Outra abordagem sed :

sed 's/\(^[^;]*\;[^;]*\).*\(\;[^;]*\;$\)//'

Resultado: cellular organisms;Eukaryota;Tribolium castaneum;

    
por 22.03.2015 / 19:03
2

Faça isso com sed

sed 's/\(\([^;]*\;\)\{2\}\).*\;\([^;]*;\)//'
    
por 22.03.2015 / 16:38
0
sed -n 's/\(;[^;]*;\).*\(;.*;\)//p' <infile

... o acima seria apenas p rint qualquer coisa para linhas de entrada que correspondam a pelo menos 4 ; chars, e para aquelas imprimiriam apenas o conteúdo que vem antes e depois e incluindo o segundo e segundo para a última ocorrência ; caracteres respectivamente.

Mais facilmente, no entanto, se você verificar primeiro que tem pelo menos quatro milhões, poderá fazer:

 sed -n '/\(;.*\)\{4\}/s/[^;]*//3p' <infile

O que primeiro garante que a linha corresponda pelo menos a 4 ; , em seguida, remove a terceira sequência que ocorre de caracteres zero-ou-mais não-ponto-e-vírgula. O teste é necessário porque a s/// ubstitution pode ser aplicada a qualquer linha que corresponda a pelo menos 2 ponto-e-vírgula - então o teste assegura um penúltimo ponto-e-vírgula ; até antes tentando a tira.

Ambas as soluções sugeridas acima imprimem apenas as linhas contra as quais a substituição é bem-sucedida. Você pode imprimir todas as linhas removendo os comandos -n e p - as substituições ainda serão tentadas e somente os resultados serão impressos para linhas com as quais eles correspondem, mas imprimirão tudo de qualquer maneira.

Claro que, se tiver certeza de sua opinião, tudo que você precisa é:

sed 's/[^;]*//3' <infile
    
por 22.03.2015 / 22:51
0

Através de python3 :

#!/bin/python3
import sys
fil = sys.argv[1]
with open(fil) as f:
    for line in f:
        m = line.strip().split(';')
        print(';'.join(m[:2]+m[-2:]))

Salve as opções acima em um arquivo chamado script.py e, em seguida, execute usando:

python3 script.py file
    
por 23.03.2015 / 05:23