Strings e textos¶
Textos estruturados¶
Existem muitos formatos de texto estruturado usados na representação de informação de caráter biológico.
Os portais de bioinformática, por exemplo a UniProt oferecem, muitas vezes, a possibilidade de transferir a informação contida em bases de dados na forma de textos. Esses textos são estruturados, seguindo formatos e regras específicos.
Exemplos:
- Sequências de ácidos nucleicos e proteínas em formato FASTA
- Alinhamentos múltiplos em formatos CLUSTAL, PIR, HSSP
- Resultados de busca na UniProt em FASTA, "Tab delimited", "Text", GFF
- ...
Obtenção de textos estruturados para processamento¶
Download manual e leitura¶
with open('c_hominis.fasta') as datafile: data = datafile.read() print(data)
>sp|A7HZZ5|ACP_CAMHC Acyl carrier protein OS=Campylobacter hominis (strain ATCC BAA-381 / LMG 19568 / NCTC 13146 / CH001A) OX=360107 GN=acpP PE=3 SV=1 MEVFEEVRDVVVEQLSVAPDAVKIDSKIIEDLGADSLDVVELVMALEEKFGIEIPDSEAE KLISIKDVVTYIENLNKNK >sp|A7I0W5|CH60_CAMHC 60 kDa chaperonin OS=Campylobacter hominis (strain ATCC BAA-381 / LMG 19568 / NCTC 13146 / CH001A) OX=360107 GN=groL PE=3 SV=1 MAKDIIFSDDARNRLYDGVKKLNDTVKVTMGPRGRNVLIQKSFGAPAITKDGVSVAKEVE LKDTIENMGAALVKEVANKTNDQAGDGTTTATVLAHAIFKEGLRNITAGANPIEVKRGMD KICADVVAELKKISKPVKDKKEIAQVATISANSDESIGKLIADAMEKVGKDGVITVEEAK SINDELNVVEGMQFDRGYLSPYFITDAEKMQVELNSPLVLLFDKKITNLKDLLPVLEQVQ KTGKPLLIIAEDIEGEALATLVVNKLRGVLNISAVKAPGFGDRRKAMLEDIAILTGGTVI SEELGRTLESASIADLGKAERILIDKDNTTIVNGAGKKDDIKARVDQIKAQIAVTSSDYD REKLQERLAKLSGGVAVIKVGAATETEMKEKKDRVDDALSATKAAVEEGIVIGGGAALIK AGNAVKENLKGDEKIGADIVKRALFAPLRQIAENAGFDAGVIANAVSINKEKAYGFDAAC GEFVNMFEAGIIDPVKVERVALQNAVSVASLLLTTEATVSEIKEDKPAMPQMPDMGGGMG GMM ... muitas outras sequências ... ... >sp|A7I1M8|LGT_CAMHC Phosphatidylglycerol--prolipoprotein diacylglyceryl transferase OS=Campylobacter hominis (strain ATCC BAA-381 / LMG 19568 / NCTC 13146 / CH001A) OX=360107 GN=lgt PE=3 SV=1 MTFWNEIYAHFDPVAFSIFGLKVHWYGLMYVLALLVALYMAKFFVKKDRLKFSNQVLENY FIWVEIGVILGARFGYILIYSNAQIFYLTHPWEIFNPFYNGKFVGISGMSYHGAVIGFII ATILFCRKKRQNLWSLLDLCALSIPLGYFFGRIGNFLNQELFGRITDVSWGILVNGELRH PSQLYEACLEGITIFLILYFYRKYKKFDGELICVYVILYAIFRFLTEFLREADVQIGYFS FGLSLGQILSVFMLILGFSAYIKLLKNSQTEQKFNQNKS
Download programático¶
import requests url = 'https://www.uniprot.org/uniprot/?query=proteome:UP000002407%20reviewed:yes&format=list' data = requests.get(url).text print(data)
A7HZZ5 A7I0W5 ... muitos outros identificadores ... ... A7I0N8 A7I1M8
Strings¶
Definição literal, iteração e indexação¶
As strings são um dos tipos de objetos mais usados na linguagem Python. É comum um programa lidar com texto, seja porque o objetivo do programa é precisamente o processamento de informação na forma textual, seja simplesmente para que os resultados de um programa sejam apresentados com pequenos textos destinados a descrever esses resultados.
Como vimos anteriormente, uma string é uma coleção de caracteres.
Uma maneira de criarmos strings num programa é defini-las literalmente, como um texto entre aspas.
Na definição literal de strings podemos delimita-las usando 3 tipos diferentes de aspas:
"
'
"""
As aspas triplas ("""
) permitem delimitar uma string contendo várias
linhas.
a = "O Neo tomou o comprimido vermelho" b ='What is the matrix?' c ="There's no spoon" d = """ Um pequeno texto que até ocupa várias linhas algumas das linhas estão em branco"""
operador +
. Função len()
¶
O operador +
serve para "juntar" várias strings, uma operação
designada por concatenação.
c = "There's no spoon" s = c + ', really, ' + 'none' + '.' print(f'c = {c}') print(f's = {s}')
c = There's no spoon c = There's no spoon, really, none.
A função len()
é uma função universal que calcula o número de elementos de qualquer coleção.
No caso das strings, o resultado é o número de caracteres.
c = "There's no spoon" n = len(c) print(f'\n"{c}" tem {n} caracteres')
"There's no spoon" tem 16 caracteres
Aliás, as strings têm muitas funções em comum com as listas:
len()
,count()
,in
,not in
- Indexação:
a[i]
- Iteração:
for i in a:
Isto acontece porque as strings se comportam como uma sequência de caracteres, tal como uma lista é uma sequência de quaisquer objetos.
Iteração e indexação.¶
Na iteração de uma string com for
percorre-se os caracteres da string, um a um.
frase = "There's no spoon" for c in frase: print(c, c, c)
T T T h h h e e e r r r e e e ' ' ' s s s n n n o o o s s s p p p o o o o o o n n n
Na indexação, cada caractere tem uma posição (a começar do zero).
frase = "There's no spoon" print(frase[0]) print(frase[5]) print(frase[-1])
T ' n
Funções associadas a strings¶
Existem muitas funções associadas a strings
Consultar a documentação oficial em docs.python.org
São cerca de 40!
Vamos ver (apenas) as seguintes:
in
,.startswith()
,.endswith()
.strip()
.count()
,.replace()
.upper()
,.lower()
.split()
,.splitlines()
,.join()
in
, .startswith()
, .endswith()
.¶
frase = "There's no spoon" if 're' in frase: print('"re" existe na frase') else: print('"re" não existe na frase')
"re" existe na frase
seq = "AUGUUCAAGGAGUAAUGCCCCCGACUA" if seq.startswith('AUG'): print('O primeiro codão é de iniciação') if seq.endswith('UAG') or seq.endswith('UAA') or seq.endswith('UGA'): print('O último codão é um codão stop')
O primeiro codão é de iniciação
.strip()
.¶
c = """ There's no spoon """ s = c.strip() print(c) print('------------------------------------') print(s)
There's no spoon ------------------------------------ There's no spoon
.upper()
, .lower()
.¶
c = " There's no spoon " c_upper = c.upper() print('c.upper():',c_upper) c_lower = c.lower() print('c.lower():',c_lower)
c.upper(): THERE'S NO SPOON c.lower(): there's no spoon
.replace()
.¶
seq = "AUGUUCAAGGAGUAAUGCCCCCGACUA" seq2 = seq.replace('U', 'T') print(seq) print(seq2)
AUGUUCAAGGAGUAAUGCCCCCGACUA ATGTTCAAGGAGTAATGCCCCCGACTA
frase = "There's no spoon" frase2 = frase.replace(' ', '') print(frase) print(frase2)
There's no spoon There'snospoon
.split()
, splitlines()
e .join()
¶
A partir de uma string, a função .split()
gera uma lista de partes,
encontrando um separador que divida a string em várias partes.
O separador a encontrar é o argumento da função.
Se não se usar um argumento, considera-se que as partes são separadas por espaços, tabs ou mudanças de linha (no inglês genericamente designados por white space)
Alguns exemplos:
frase = "There's no spoon" x = frase.split() print(x)
["There's", 'no', 'spoon']
frase = "There's no spoon" x = frase.split('s') print(x)
["There'", ' no ', 'poon']
frase = "There's no spoon" x = frase.split('o') print(x)
["There's n", ' sp', '', 'n']
frase = "There's no spoon" x = frase.split('n') print(x)
["There's ", 'o spoo', '']
A função .join()
é uma espécie de inversa de .split()
: transforma
uma lista de strings numa única string, interpondo um
separador:
aas = ['Arg', 'Tyr', 'Gly', 'Asp'] print(" ".join(aas)) print("-".join(aas)) print("".join(aas)) print("+".join(aas)) print("-CONH-".join(aas))
Arg Tyr Gly Asp Arg-Tyr-Gly-Asp ArgTyrGlyAsp Arg+Tyr+Gly+Asp Arg-CONH-Tyr-CONH-Gly-CONH-Asp
Problema: transformar AUGUUCAAGGAGUAAUGCCCCCGACUA
em
AUG-UUC-AAG-GAG-UAA-UGC-CCC-CGA-CUA
s = "AUGUUCAAGGAGUAAUGCCCCCGACUA" print(s) starts = range(0, len(s), 3) codoes = [] for i in starts: # i é o início de cada codão (c) c = s[i] + s[i+1] + s[i+2] codoes.append(c) print(codoes) final = "-".join(codoes) print(final)
AUGUUCAAGGAGUAAUGCCCCCGACUA ['AUG', 'UUC', 'AAG', 'GAG', 'UAA', 'UGC', 'CCC', 'CGA', 'CUA'] AUG-UUC-AAG-GAG-UAA-UGC-CCC-CGA-CUA
Ou, usando uma lista em compreensão:
s = "AUGUUCAAGGAGUAAUGCCCCCGACUA" cods = [s[i] + s[i+1] + s[i+2] for i in range(0, len(s), 3)] print(s) print(cods) print( "-".join(cods) )
AUGUUCAAGGAGUAAUGCCCCCGACUA ['AUG', 'UUC', 'AAG', 'GAG', 'UAA', 'UGC', 'CCC', 'CGA', 'CUA'] AUG-UUC-AAG-GAG-UAA-UGC-CCC-CGA-CUA
Tem de haver uma maneira mais sucinta de de juntar vários caracteres consecutivos!
A função .splitlines()
é equivalente a .split('\n')
:
seq = """>sp|A7I178|ATPE_CAMHC ATP synthase epsilon chain MDKLFLEIVTPEGEIFANDVKSVQVPGCEGEFGILPRHATLVTTLNAGVIEVINLDGTKD MIAIDDGGCIKVAEDKTTILANGAVYIGGSNESEIAISLQKAKELVKSMSSNTIVYATTI AKIDEQVRQK""" lines = seq.splitlines() print(lines)
['>sp|A7I178|ATPE_CAMHC ATP synthase epsilon chain', 'MDKLFLEIVTPEGEIFANDVKSVQVPGCEGEFGILPRHATLVTTLNAGVIEVINLDGTKD', 'MIAIDDGGCIKVAEDKTTILANGAVYIGGSNESEIAISLQKAKELVKSMSSNTIVYATTI', 'AKIDEQVRQK']
É muito interessante o facto de podermos usar funções de strings em conjunção com listas em compreensão:
Problema: num texto com várias linhas, obter numa lista as linhas que começam por uma vogal e têm menos de 20 caracteres
txt = """ Um pequeno texto que até ocupa várias linhas mas haverá Algumas em branco""" a = [s.strip() for s in txt.splitlines()] print(a) a = [s for s in a if 0 < len(s) < 20] print(a) a = [s for s in a if s[0].lower() in 'aeiou'] print(a)
['', 'Um pequeno texto que até', 'ocupa várias', 'linhas', '', 'mas haverá', 'Algumas em branco'] ['ocupa várias', 'linhas', 'mas haverá', 'Algumas em branco'] ['ocupa várias', 'Algumas em branco']
Slices¶
Já vimos que podemos indexar listas e strings, usando []
e a posição
do elemento.
Os []
podem ser usados para um outro tipo de indexação de listas ou
strings: os slices (em português: "fatias").
Os slices extraem uma parte de uma lista ou string que podem ter mais de um elemento.
A forma geral é [início : fim(exclusivé) : passo]
. O passo
é
opcional.
a = "O Neo tomou o comprimido vermelho" # 012345678901234567890123456789012 print(a[2:5]) print(a[0:5]) print(a[6:-1])
Neo O Neo tomou o comprimido vermelh
a = "O Neo tomou o comprimido vermelho" # 012345678901234567890123456789012 print(a[ :5]) print(a[6: ]) print(a[ : ]) print(a[0:12:2])
O Neo tomou o comprimido vermelho O Neo tomou o comprimido vermelho ONotmu
seq = "AUGUUCAAGGAGUAAUGCCCCCGACUA" c = seq[ :3] d = seq[-3: ] print('O primeiro codão é', c) print('O último codão é', d)
O primeiro codão é AUG O último codão é CUA
Problema: transformar AUGUUCAAGGAGUAAUGCCCCCGACUA
em
AUG-UUC-AAG-GAG-UAA-UGC-CCC-CGA-CUA
s = "AUGUUCAAGGAGUAAUGCCCCCGACUA" starts = range(0, len(s), 3) # na versão anterior: # cods = [s[i] + s[i+1] + s[i+2] for i in starts] # usando um slice cods = [s[i:i+3] for i in starts] print(s) print(cods) print( "-".join(cods) )
AUGUUCAAGGAGUAAUGCCCCCGACUA AUG-UUC-AAG-GAG-UAA-UGC-CCC-CGA-CUA
Usando uma lista em compreensão como argumento da função .join()
o
programa pode ficar mais compacto:
s = "AUGTTCAAGGAGUAAUGCCCCCGACUA" sf = "-".join([s[i:i+3] for i in range(0,len(s),3)]) print(s) print(sf)
AUGTTCAAGGAGUAAUGCCCCCGACUA AUG-TTC-AAG-GAG-UAA-UGC-CCC-CGA-CUA
Os slices também funcionam com listas
aas = ['Arg', 'Tyr', 'Gly', 'Asp'] s1 = aas[ :2] s2 = aas[-2: ] s3 = aas[ : :2] print(s1) print(s2) print(s3)
['Arg', 'Tyr'] ['Gly', 'Asp'] ['Arg', 'Gly']
Importante
Os slices produzem sempre novos objetos
No caso de uma lista, podemos atribuír valores a um slice da lista, mudando alguns elementos de uma só vez:
nums = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] # 0 1 2 3 4 5 6 7 8 9 print(nums) nums[3:8] = range(10, 15) print(nums)
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4] [1, 2, 2, 10, 11, 12, 13, 14, 4, 4]
Problema: Converter uma sequência com códigos de uma letra de aminoácidos para códigos de 3 letras, usando um dicionário para a conversão.
trans = {'A': 'Ala', 'C': 'Cys', 'E': 'Glu', 'D': 'Asp', 'G': 'Gly', 'F': 'Phe', 'I': 'Ile', 'H': 'His', 'K': 'Lys', 'M': 'Met', 'L': 'Leu', 'N': 'Asn', 'Q': 'Gln', 'P': 'Pro', 'S': 'Ser', 'R': 'Arg', 'T': 'Thr', 'W': 'Trp', 'V': 'Val', 'Y': 'Tyr'} s1 = 'ADKLITCWFHHWE' s3 = '-'.join([trans[aa] for aa in s1]) print(s1, 'é o mesmo que', s3)
ADKLITCWFHHWE é o mesmo que Ala-Asp-Lys-Leu-Ile-Thr-Cys-Trp-Phe-His-His-Trp-Glu
Problema: calcular o complemento reverso de uma sequência. Apresentar a sequência de partida e o complemento reverso no formato em que os codões são separados por um hífen.
Para resolver este problema podemos usar a função reversed()
. Esta função
aplica-se a qualquer coleção e "gera" os elementos da coleção pela ordem inversa.
Aplicando depois a função ''.join()
, com o separador "vazio", ao resultado
da função reversed()
podemos inverter uma string.
trans = {'A':'T', 'T':'A', 'C':'G', 'G':'C'} seq = "ATGGTTACCTAGTATTTAGGATTA" # inverter a sequência seq_rev = ''.join(reversed(seq)) # traduzir para a sequência complementar comp = ''.join([trans[b] for b in seq_rev]) # Apresentar com os codões separados por hífen print("Seq:") print('-'.join([seq[i:i+3] for i in range(0,len(seq),3)])) print("\nComplemento reverso:") print('-'.join([comp[i:i+3] for i in range(0,len(comp),3)]))
Seq: ATG-GTT-ACC-TAG-TAT-TTA-GGA-TTA Complemento reverso: TAA-TCC-TAA-ATA-CTA-GGT-AAC-CAT
"Imutabilidade" das strings¶
As strings são imutáveis.
Isto significa que (ao contrário das listas e dicionários) não existem funções para modificar uma string.
Não existe, por exemplo, s.append('a')
.
Todas as operações com strings resultam numa string nova, à qual é, geralmente, atribuído um nome (mesmo que seja o mesmo nome da string original)
Podemos, por isso, usar s = s + 'a'
Formatação de strings com .format()
¶
x = 11 y = 20 z = 3 print('x = {}, y = {}, z = {}'.format(x, y, z))
x = 11, y = 20, z = 3
d = {'H':1, 'Li':3, 'Na':11, 'K':19} for k, v in d.items(): print('O elemento com n = {1} é o {0}'.format(k, v))
O elemento com n = 1 é o H O elemento com n = 3 é o Li O elemento com n = 11 é o Na O elemento com n = 19 é o K
d = {'H':1, 'Li':3, 'Na':11, 'K':19} for k, v in d.items(): print('O elemento com n = {1:2} é o {0}'.format(k, v))
O elemento com n = 1 é o H O elemento com n = 3 é o Li O elemento com n = 11 é o Na O elemento com n = 19 é o K
d = {'H':1, 'Li':3, 'Na':11, 'K':19} for k, v in d.items(): print('O elemento com n = {1:<2} é o {0}'.format(k, v))
O elemento com n = 1 é o H O elemento com n = 3 é o Li O elemento com n = 11 é o Na O elemento com n = 19 é o K
import math log2 = math.log(2) soma = 0.0 # acumula a soma parcial da série for i in range(1, 21): soma = soma + (-1)**(i+1) / i dif = abs(soma - log2) print(i , soma , dif)
1 1.0 0.3068528194400547 2 0.5 0.1931471805599453 3 0.8333333333333333 0.14018615277338797 4 0.5833333333333333 0.10981384722661203 5 0.7833333333333332 0.09018615277338793 6 0.6166666666666666 0.0764805138932787 7 0.7595238095238095 0.0663766289638642 8 0.6345238095238095 0.058623371036135796 9 0.7456349206349207 0.052487740074975364 10 0.6456349206349207 0.047512259925024614 11 0.7365440115440116 0.043396830984066326 12 0.6532106782106782 0.039936502349267045 13 0.7301337551337552 0.03698657457380994 14 0.6587051837051838 0.03444199685476146 15 0.7253718503718505 0.03222466981190519 16 0.6628718503718505 0.030275330188094807 17 0.7216953797836152 0.028548199223669912 18 0.6661398242280596 0.027007356331885668 19 0.718771403175428 0.025624222615482695 20 0.6687714031754279 0.02437577738451735
import math log2 = math.log(2) soma = 0.0 # acumula a soma parcial da série print('{:>4} {:^9} {:^9}'.format('n' , 'S' , 'dif')) for i in range(1, 21): soma = soma + (-1)**(i+1) / i dif = abs(soma - log2) print('{:4d} {:9.6f} {:9.6f}'.format(i,soma,dif))
n S dif 1 1.000000 0.306853 2 0.500000 0.193147 3 0.833333 0.140186 4 0.583333 0.109814 5 0.783333 0.090186 6 0.616667 0.076481 7 0.759524 0.066377 8 0.634524 0.058623 9 0.745635 0.052488 10 0.645635 0.047512 11 0.736544 0.043397 12 0.653211 0.039937 13 0.730134 0.036987 14 0.658705 0.034442 15 0.725372 0.032225 16 0.662872 0.030275 17 0.721695 0.028548 18 0.666140 0.027007 19 0.718771 0.025624 20 0.668771 0.024376
Consultar a documentação da Format Specification Mini-Language