J'ai un peu de difficulté à obtenir une expression rationnelle Python lors de la comparaison avec un texte couvrant plusieurs lignes. Le texte d'exemple est ('\ n' est une nouvelle ligne)
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).
Je voudrais capturer deux choses: la partie 'some_Varying_TEXT' et toutes les lignes de texte majuscule qui viennent deux lignes en dessous dans une capture (je peux supprimer les caractères de nouvelle ligne plus tard). J'ai essayé avec quelques approches:
re.compile(r"^>(\w+)$$([.$]+)^$", re.MULTILINE) # try to capture both parts
re.compile(r"(^[^>][\w\s]+)$", re.MULTILINE|re.DOTALL) # just textlines
et beaucoup de variations de celui-ci sans aucune chance. Le dernier semble correspondre aux lignes de texte une par une, ce qui n’est pas ce que je veux vraiment. Je peux attraper la première partie, pas de problème, mais je n'arrive pas à attraper les 4-5 lignes de texte en majuscule. Je voudrais que match.group (1) soit some_Varying_Text et que group (2) soit line1 + line2 + line3 + etc jusqu'à ce que la ligne vide soit rencontrée.
Si quelqu'un est curieux, il est supposé être une séquence d'acides aminés constituant une protéine.
Essaye ça:
re.compile(r"^(.+)\n((?:\n.+)+)", re.MULTILINE)
Je pense que votre plus gros problème est que vous attendez le ^
et $
_ ancres pour correspondre aux sauts de ligne, mais ils ne le font pas. En mode multiligne, ^
correspond à la position immédiatement suivant une nouvelle ligne et $
correspond à la position immédiatement previous une nouvelle ligne.
Sachez également qu’une nouvelle ligne peut consister en un saut de ligne (\ n), un retour chariot (\ r) ou un retour chariot + retour à la ligne (\ r\n). Si vous n'êtes pas certain que votre texte cible utilise uniquement des sauts de ligne, vous devez utiliser cette version plus inclusive de l'expression régulière:
re.compile(r"^(.+)(?:\n|\r\n?)((?:(?:\n|\r\n?).+)+)", re.MULTILINE)
BTW, vous ne voulez pas utiliser le modificateur DOTALL ici; vous vous fiez au fait que le point correspond à tout sauf nouvelles lignes.
Cela fonctionnera:
>>> import re
>>> rx_sequence=re.compile(r"^(.+?)\n\n((?:[A-Z]+\n)+)",re.MULTILINE)
>>> rx_blanks=re.compile(r"\W+") # to remove blanks and newlines
>>> text="""Some varying text1
...
... AAABBBBBBCCCCCCDDDDDDD
... EEEEEEEFFFFFFFFGGGGGGG
... HHHHHHIIIIIJJJJJJJKKKK
...
... Some varying text 2
...
... LLLLLMMMMMMNNNNNNNOOOO
... PPPPPPPQQQQQQRRRRRRSSS
... TTTTTUUUUUVVVVVVWWWWWW
... """
>>> for match in rx_sequence.finditer(text):
... title, sequence = match.groups()
... title = title.strip()
... sequence = rx_blanks.sub("",sequence)
... print "Title:",title
... print "Sequence:",sequence
... print
...
Title: Some varying text1
Sequence: AAABBBBBBCCCCCCDDDDDDDEEEEEEEFFFFFFFFGGGGGGGHHHHHHIIIIIJJJJJJJKKKK
Title: Some varying text 2
Sequence: LLLLLMMMMMMNNNNNNNOOOOPPPPPPPQQQQQQRRRRRRSSSTTTTTUUUUUVVVVVVWWWWWW
Quelques explications sur cette expression régulière pourraient être utiles: ^(.+?)\n\n((?:[A-Z]+\n)+)
^
) Signifie "à partir du début d'une ligne". Sachez que cela ne correspond pas à la nouvelle ligne (idem pour $: cela signifie "juste avant une nouvelle ligne", mais cela ne correspond pas à la nouvelle ligne elle-même).(.+?)\n\n
Signifie "faites correspondre le moins de caractères possible (tous les caractères sont autorisés) jusqu'à ce que vous atteigniez deux nouvelles lignes". Le résultat (sans les nouvelles lignes) est placé dans le premier groupe.[A-Z]+\n
Signifie "faire correspondre autant de lettres majuscules que possible jusqu'à atteindre une nouvelle ligne. Ceci définit ce que j'appellerai une ligne de texte .((?:
textline )+)
Signifie qu’il faut faire correspondre une ou plusieurs textlines mais ne mettez pas chaque ligne dans un groupe. Au lieu de cela, mettez tous les textlines dans un groupe.\n
Dans l'expression régulière si vous souhaitez imposer une double nouvelle ligne à la fin.\n
Ou \r
Ou \r\n
), Corrigez simplement l'expression régulière en remplaçant chaque occurrence de \n
Par (?:\n|\r\n?)
.Si chaque fichier ne contient qu'une séquence d'acides aminés, je n'utiliserais pas du tout d'expressions régulières. Juste quelque chose comme ça:
def read_amino_acid_sequence(path):
with open(path) as sequence_file:
title = sequence_file.readline() # read 1st line
aminoacid_sequence = sequence_file.read() # read the rest
# some cleanup, if necessary
title = title.strip() # remove trailing white spaces and newline
aminoacid_sequence = aminoacid_sequence.replace(" ","").replace("\n","")
return title, aminoacid_sequence
trouver:
^>([^\n\r]+)[\n\r]([A-Z\n\r]+)
\ 1 = some_varying_text
\ 2 = lignes de tous les CAPS
Edit (preuve que cela fonctionne):
text = """> some_Varying_TEXT
DSJFKDAFJKDAFJDSAKFJADSFLKDLAFKDSAF
GATACAACATAGGATACA
GGGGGAAAAAAAATTTTTTTTT
CCCCAAAA
> some_Varying_TEXT2
DJASDFHKJFHKSDHF
HHASGDFTERYTERE
GAGAGAGAGAG
PPPPPAAAAAAAAAAAAAAAP
"""
import re
regex = re.compile(r'^>([^\n\r]+)[\n\r]([A-Z\n\r]+)', re.MULTILINE)
matches = [m.groups() for m in regex.finditer(text)]
for m in matches:
print 'Name: %s\nSequence:%s' % (m[0], m[1])
Voici une expression régulière correspondant à un bloc de texte multiligne:
import re
result = re.findall('(startText)(.+)((?:\n.+)+)(endText)',input)
Ma préférence.
lineIter= iter(aFile)
for line in lineIter:
if line.startswith( ">" ):
someVaryingText= line
break
assert len( lineIter.next().strip() ) == 0
acids= []
for line in lineIter:
if len(line.strip()) == 0:
break
acids.append( line )
À ce stade, vous avez someVaryingText en tant que chaîne et les acides en tant que liste de chaînes. Vous pouvez faire "".join( acids )
pour créer une seule chaîne.
Je trouve cela moins frustrant (et plus flexible) que les regex multilignes.