Estou tendo problemas para fazer um regex Python funcionar ao comparar com texto que se estende por várias linhas. O texto de exemplo é ('\ n' é uma nova linha)
some Varying TEXT\n
\n
DSJFKDAFJKDAFJDSAKFJADSFLKDLAFKDSAF\n
[more of the above, ending with a newline]\n
[yep, there is a variable number of lines here]\n
\n
(repeat the above a few hundred times).
Eu gostaria de capturar duas coisas: a parte 'some_Varying_TEXT' e todas as linhas de texto em maiúsculas que vêm duas linhas abaixo dele em uma captura (posso retirar os caracteres de nova linha mais tarde). Eu tentei com algumas abordagens:
re.compile(r"^>(\w+)$$([.$]+)^$", re.MULTILINE) # try to capture both parts
re.compile(r"(^[^>][\w\s]+)$", re.MULTILINE|re.DOTALL) # just textlines
e muitas variações disso sem sorte. O último parece corresponder às linhas do texto uma a uma, o que não é o que eu realmente quero. Consigo captar a primeira parte, sem problemas, mas não consigo captar as 4-5 linhas de texto em maiúsculas. Eu gostaria que match.group (1) fosse some_Varying_Text e group (2) fosse line1 + line2 + line3 + etc até que a linha vazia fosse encontrada.
Se alguém estiver curioso, é suposto ser uma sequência de aminoácidos que constituem uma proteína.
>
caractere principal . Deveria?Respostas:
Experimente isto:
Acho que seu maior problema é que você espera que as âncoras
^
e se$
igualem aos avanços de linha, mas não são. No modo multilinha,^
corresponde à posição imediatamente após uma nova linha e$
corresponde à posição imediatamente anterior a uma nova linha.Esteja ciente, também, que uma nova linha pode consistir em um avanço de linha (\ n), um retorno de carro (\ r) ou um retorno de carro + avanço de linha (\ r \ n). Se você não tem certeza de que seu texto de destino usa apenas alimentações de linha, você deve usar esta versão mais abrangente do regex:
BTW, você não deseja usar o modificador DOTALL aqui; você está contando com o fato de que o ponto corresponde a tudo, exceto às novas linhas.
fonte
Isso vai funcionar:
Alguma explicação sobre essa expressão regular pode ser útil:
^(.+?)\n\n((?:[A-Z]+\n)+)
^
) significa "começando no início de uma linha". Esteja ciente de que não corresponde à nova linha em si (o mesmo para $: significa "logo antes de uma nova linha", mas não corresponde à própria nova linha).(.+?)\n\n
significa "combinar o mínimo de caracteres possível (todos os caracteres são permitidos) até chegar a duas novas linhas". O resultado (sem as novas linhas) é colocado no primeiro grupo.[A-Z]+\n
significa "combinar tantas letras maiúsculas quanto possível até chegar a uma nova linha. Isso define o que chamarei de linha de texto .((?:
linha de texto)+)
significa corresponder a uma ou mais linhas de texto, mas não colocar cada linha em um grupo. Em vez disso, coloque todas as linhas de texto em um grupo.\n
na expressão regular se quiser impor uma nova linha dupla no final.\n
ou\r
ou\r\n
), apenas corrija a expressão regular substituindo todas as ocorrências de\n
por(?:\n|\r\n?)
.fonte
Se cada arquivo tivesse apenas uma sequência de aminoácidos, eu não usaria expressões regulares. Algo assim:
fonte
encontrar:
\ 1 = algum_texto_variável
\ 2 = linhas de todos os CAPS
Editar (prova de que isso funciona):
fonte
A seguir está uma expressão regular que corresponde a um bloco de texto de várias linhas:
fonte
Minha preferência.
Neste ponto, você tem algum texto variável como string e os ácidos como uma lista de strings. Você pode fazer
"".join( acids )
para fazer uma única corda.Acho isso menos frustrante (e mais flexível) do que regexes de várias linhas.
fonte