Extrai parte da string das linhas de cada coluna

2

Eu tenho um arquivo de texto com > 20.000 linhas, assim:

7   128550681   128550681   Intron:1:36:RETAINED-RETAINED;Transcript:NM_001135914.1;Gene:KCP:protein_coding 1   1   0   0
1   17718672    17718672    Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding  1   1   0   0
1   17718672    17718672    Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding  1   1   0   0
4   86035   86035   Exon:4:5:RETAINED;Transcript:NM_001286052.1;Gene:ZNF595:protein_coding  1   1   0   0
3   12942851    12942851    Intron:14:14:SKIPPED-ALTTENATIVE_3SS;Transcript:NM_001134382.2;Gene:IQSEC1:protein_coding   1   1   0   0

O que eu preciso é que a quarta coluna contenha apenas Gene: genename, então a saída é assim:

7   128550681   128550681   Gene:KCP    1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
4   86035   86035   Gene:ZNF595 1   1   0   0
3   12942851    12942851    Gene:IQSEC1 1   1   0   0

* O problema é Gene:genename nem sempre no mesmo local ao tentar dividir por : ou ;

Conheço o awk / sed muito básico como selecionar uma coluna específica, como grep linhas que contêm algum padrão

    
por Sara Wasl 13.07.2018 / 20:50

5 respostas

2

Consegui fazer isso com o seguinte comando awk :

awk '{sub(/^.*;/,"",$4); print}' input

Isso removerá tudo da coluna 4 até o último ; , o que pode não funcionar para você (veja o comentário da steeldriver). Nesse caso, atualize sua pergunta com esclarecimentos.

    
por 13.07.2018 / 20:56
2

Usando awk somente com construções definidas POSIX,

awk 'match($4, /Gene:(.+)\:/){ $4=substr($4, RSTART, RLENGTH-1) }1' file

Para tornar a saída um pouco mais alinhada, canalize a saída para | column -t , o que separará suas colunas. Se você não tiver certeza da posição de Gene:genename em sua linha, altere o awk para procurar o padrão em qualquer lugar dentro da linha e modifique a quarta coluna com o valor necessário. Mudar para $4 para $0 (toda a linha) deve funcionar bem.

awk 'match($0, /Gene:(.+)\:/){ $4=substr($0, RSTART, RLENGTH-1) }1' file
    
por 13.07.2018 / 20:58
0
perl -pale 's#(?:\H+\h+){3}\K\H+#($F[3] =~ /(?:^|;)(Gene:[^:]+)/)[0]#e' input-file.txt 

° no caso de nenhuma localização fixa do gene no quarto campo, podemos fazer como acima.

° nos concentramos no quarto campo por meio de regex (?:\H+\h+){3}\K\H+ e substituímos imediatamente por outro regex usado na parte substituta do comando s///e .

    
por 13.07.2018 / 21:30
0

Tratar a coluna quatro como uma lista de strings delimitadas por ; ou : e substituir toda a coluna pela string Gene e pela seguinte (o nome do gene) dividindo primeiro esse campo e, em seguida, localizando o nós queremos:

$ awk -vOFS='\t' '{ split($4,a,"[;:]"); for (i in a) if (a[i]=="Gene") { $4 = a[i] ":" a[i+1]; break } } 1' file
7       128550681       128550681       Gene:KCP        1       1       0       0
1       17718672        17718672        Gene:PADI6      1       1       0       0
1       17718672        17718672        Gene:PADI6      1       1       0       0
4       86035   86035   Gene:ZNF595     1       1       0       0
3       12942851        12942851        Gene:IQSEC1     1       1       0       0
    
por 15.07.2018 / 08:11
0

Perl:

perl -F'\h+' -lane '
    for ( $F[3] ) {
        my $a = index(";$_", ";Gene:"     );
        my $b = index(";$_", ":",    $a+6 );
        $_ = substr(";$_", $a+1, $b-$a-1);
    }
    print join "\t", @F;
' input-file.txt

Saída:

7   128550681   128550681   Gene:KCP    1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
1   17718672    17718672    Gene:PADI6  1   1   0   0
4   86035   86035   Gene:ZNF595 1   1   0   0
3   12942851    12942851    Gene:IQSEC1 1   1   0   0
$   128550681   128550681   Gene:$$$    1   1   0   0

Explicação:

  • perl opções:
    • -n = > invocar uma leitura linha a linha da entrada.
    • -F = > fará FS = horizontal whitespace .
    • -a = > dividir cada linha em campos (com base em qualquer FS definido pela opção -F ou um único espaço por padrão) e armazená-los na matriz @F .
    • -l = > fará RS = ORS = "\n" .
    • -e = > o que segue é para ser tratado como Perl code e aplicado em cada linha, a.ka., record.
  • data structures envolvido:
    • @F = > o array preenchido com os campos obtido pela divisão do registro. Indexado de 0. Portanto, $F[3] é o quarto campo no registro.
    • $a = > mantém a posição da substring ;Gene: no quarto campo.
    • $b = > mantém a posição da substring : no quarto campo, que é encontrado procurando 6 dígitos APÓS a posição de ;Gene: . IOW, ele encontra o segundo : após o ;Gene . Nota: Nós colocamos um ponto-e-vírgula na string de busca, isto é, $F[3] , já que a posição de Gene: pode estar em qualquer lugar, então pode muito bem estar no começo do quarto campo também. Isso é para cuidar dessa eventualidade.
    • $_ = > mantém a versão localizada de $F[3] dentro de um loop for . o substr builtin extrairá as informações de gene:... e as armazenará novamente em $F[3] .
    • Nota: o qualificador my antes das definições de variável para $a,$b indica que elas sejam variáveis léxicas cujo escopo está limitado apenas ao loop for .
    • Nota: $_ dentro do loop for NÃO se refere ao registro / linha atual. Ele foi sobrecarregado e localizado durante a duração do loop for para ser $F[3] .

GNU Sed:

sed -Ee '
    s/\S+/\n&\n/4
    s/\n(.*;)?(Gene:[^:]+):.*\n//
' input-file.txt

Explicação:

  • Marcamos o quarto campo com novas linhas.
  • Após ter estabelecido a região na linha atual, nós analisamos os dados necessários, no nosso caso, Gene: e, depois disso, as many non colons we meet on the way before we hit the next colon .
  • Este método não perturba o espaçamento existente entre os vários campos. Isso pode ou não ser importante.
  • Nota FYI: Assume um único gene no quarto campo. Para múltiplos genes, ele não irá errar ou avisar, em vez de escolher silenciosamente o último gene do quarto campo desse registro.
por 16.07.2018 / 10:12