Regulärer Ausdruck, der einem mehrzeiligen Textblock entspricht

Lesezeit: 6 Minuten

Regularer Ausdruck der einem mehrzeiligen Textblock entspricht
Jan

Ich habe ein paar Probleme damit, einen Python-Regex zum Laufen zu bringen, wenn ich mit Text vergleiche, der sich über mehrere Zeilen erstreckt. Der Beispieltext ist (‘n’ ist ein Zeilenumbruch)

some Varying TEXTn
n
DSJFKDAFJKDAFJDSAKFJADSFLKDLAFKDSAFn
[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).

Ich möchte zwei Dinge erfassen: den Teil „some_Varying_TEXT“ und alle Textzeilen in Großbuchstaben, die zwei Zeilen darunter in einer Erfassung kommen (ich kann die Zeilenumbruchzeichen später entfernen). Ich habe es mit ein paar Ansätzen versucht:

re.compile(r"^>(w+)$$([.$]+)^$", re.MULTILINE) # try to capture both parts
re.compile(r"(^[^>][ws]+)$", re.MULTILINE|re.DOTALL) # just textlines

und viele Variationen davon ohne Glück. Der letzte scheint die Textzeilen eine nach der anderen abzugleichen, was ich nicht wirklich will. Ich kann den ersten Teil verstehen, kein Problem, aber ich kann die 4-5 Zeilen Text in Großbuchstaben nicht verstehen. Ich möchte, dass match.group(1) some_Varying_Text und group(2) line1+line2+line3+etc ist, bis die leere Zeile gefunden wird.

Falls es jemanden interessiert, es soll eine Abfolge von Aminosäuren sein, aus denen ein Protein besteht.

  • Gibt es außer der ersten Zeile und dem Großbuchstaben noch etwas anderes in der Datei? Ich bin mir nicht sicher, warum Sie eine Regex verwenden würden, anstatt den gesamten Text an Zeilenumbruchzeichen aufzuteilen und das erste Element als “some_Varying_TEXT” zu nehmen.

    – Onkel Zeiv

    25. Februar 09 um 19:20 Uhr

  • ja, Regex sind dafür das falsche Werkzeug.

    Benutzer3850

    25. Februar 09 um 20:25 Uhr

  • Ihr Beispieltext hat keinen Zeilenabstand > Charakter. Sollte es?

    – MiniQuark

    25. Februar 09 um 20:39 Uhr

Regularer Ausdruck der einem mehrzeiligen Textblock entspricht
Alan Moore

Versuche dies:

re.compile(r"^(.+)n((?:n.+)+)", re.MULTILINE)

Ich denke, dein größtes Problem ist, dass du das erwartest ^ und $ Anker, um Zeilenumbrüchen zu entsprechen, aber sie tun es nicht. Im mehrzeiligen Modus ^ passt sofort auf die Position folgende ein Zeilenumbruch und $ passt sofort auf die Position vorangehend ein Zeilenumbruch.

Beachten Sie auch, dass ein Zeilenumbruch aus einem Zeilenvorschub bestehen kann (n), ein Wagenrücklauf (r) oder ein Wagenrücklauf+Zeilenvorschub (rn). Wenn Sie nicht sicher sind, ob Ihr Zieltext nur Zeilenvorschübe verwendet, sollten Sie diese umfassendere Version der Regex verwenden:

re.compile(r"^(.+)(?:n|rn?)((?:(?:n|rn?).+)+)", re.MULTILINE)

Übrigens, Sie möchten hier nicht den DOTALL-Modifikator verwenden; Sie verlassen sich darauf, dass der Punkt zu allem passt außer Zeilenumbrüche.

  • Möglicherweise möchten Sie den zweiten Punkt in der Regex durch ersetzen [A-Z] wenn Sie nicht möchten, dass dieser reguläre Ausdruck mit jeder Textdatei mit einer leeren zweiten Zeile übereinstimmt. 😉

    – MiniQuark

    25. Februar 09 um 20:36 Uhr

  • Mein Eindruck ist, dass die Zieldateien einem bestimmten (und sich wiederholenden) Muster aus leeren und nicht leeren Zeilen entsprechen, sodass eine Angabe nicht erforderlich sein sollte [A-Z]aber es wird wahrscheinlich auch nicht schaden.

    – Alan Moore

    25. Februar 09 um 21:13 Uhr

  • Diese Lösung hat wunderbar funktioniert. Nebenbei entschuldige ich mich dafür, dass ich den Sachverhalt offensichtlich nicht ausreichend aufgeklärt habe (und auch für die Verspätung dieser Antwort). Danke für Ihre Hilfe!

    – Jan

    3. März 09 um 22:18 Uhr

Regularer Ausdruck der einem mehrzeiligen Textblock entspricht
MiniQuark

Das wird funktionieren:

>>> import re
>>> rx_sequence=re.compile(r"^(.+?)nn((?:[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

Einige Erläuterungen zu diesem regulären Ausdruck könnten hilfreich sein: ^(.+?)nn((?:[A-Z]+n)+)

  • Das erste Zeichen (^) bedeutet „beginnend am Anfang einer Zeile“. Beachten Sie, dass es nicht mit dem Zeilenumbruch selbst übereinstimmt (dasselbe gilt für $: es bedeutet “kurz vor einem Zeilenumbruch”, aber es stimmt nicht mit dem Zeilenumbruch selbst überein).
  • Dann (.+?)nn bedeutet “passen Sie so wenig Zeichen wie möglich an (alle Zeichen sind erlaubt), bis Sie zwei Zeilenumbrüche erreichen”. Das Ergebnis (ohne die Zeilenumbrüche) wird in die erste Gruppe gestellt.
  • [A-Z]+n bedeutet “passen Sie so viele Großbuchstaben wie möglich an, bis Sie einen Zeilenumbruch erreichen. Dies definiert, was ich a nennen werde Textzeile.
  • ((?:Textzeile)+) bedeutet Übereinstimmung mit einem oder mehreren Textzeilen aber fügen Sie nicht jede Zeile in eine Gruppe ein. Setzen Sie stattdessen alle das Textzeilen in einer Gruppe.
  • Sie könnten ein Finale hinzufügen n im regulären Ausdruck, wenn Sie am Ende einen doppelten Zeilenumbruch erzwingen möchten.
  • Wenn Sie sich nicht sicher sind, welche Art von Zeilenumbruch Sie erhalten (n oder r oder rn) korrigieren Sie dann einfach den regulären Ausdruck, indem Sie jedes Vorkommen von ersetzen n durch (?:n|rn?).

  • match() gibt nur eine Übereinstimmung ganz am Anfang des Zieltextes zurück, aber das OP sagte, dass es Hunderte von Übereinstimmungen pro Datei geben würde. Ich denke, Sie würden stattdessen finditer() wollen.

    – Alan Moore

    25. Februar 09 um 21:24 Uhr

1643907368 580 Regularer Ausdruck der einem mehrzeiligen Textblock entspricht
Punnerud

Das Folgende ist ein regulärer Ausdruck, der mit einem mehrzeiligen Textblock übereinstimmt:

import re
result = re.findall('(startText)(.+)((?:n.+)+)(endText)',input)

  • Dies ist meiner Meinung nach die beste und direkteste Antwort.

    – pauljohn32

    25. März 21 um 15:43 Uhr

Wenn jede Datei nur eine Sequenz von Aminosäuren enthält, würde ich überhaupt keine regulären Ausdrücke verwenden. Nur so etwas:

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

1643907368 108 Regularer Ausdruck der einem mehrzeiligen Textblock entspricht
Jason Coon

finden:

^>([^nr]+)[nr]([A-Znr]+)

1 = etwas_variierender_Text

2 = Zeilen nur GROSSBUCHSTABEN

Bearbeiten (Beweis, dass dies funktioniert):

text = """> some_Varying_TEXT

DSJFKDAFJKDAFJDSAKFJADSFLKDLAFKDSAF
GATACAACATAGGATACA
GGGGGAAAAAAAATTTTTTTTT
CCCCAAAA

> some_Varying_TEXT2

DJASDFHKJFHKSDHF
HHASGDFTERYTERE
GAGAGAGAGAG
PPPPPAAAAAAAAAAAAAAAP
"""

import re

regex = re.compile(r'^>([^nr]+)[nr]([A-Znr]+)', re.MULTILINE)
matches = [m.groups() for m in regex.finditer(text)]

for m in matches:
    print 'Name: %snSequence:%s' % (m[0], m[1])

  • Leider passt dieser reguläre Ausdruck auch auf Gruppen von Großbuchstaben, die durch Leerzeilen getrennt sind. Es könnte jedoch keine große Sache sein.

    – MiniQuark

    25. Februar 09 um 20:27 Uhr

  • Sieht so aus, als ob coonj FASTA-Dateien mag. 😉

    – Andreas Dalke

    26. Februar 09 um 13:21 Uhr

1643907368 120 Regularer Ausdruck der einem mehrzeiligen Textblock entspricht
S. Lott

Meine Vorliebe.

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 )

An diesem Punkt haben Sie someVaryingText als String und die Säuren als Liste von Strings. Du kannst tun "".join( acids ) um eine einzelne Saite zu machen.

Ich finde das weniger frustrierend (und flexibler) als mehrzeilige reguläre Ausdrücke.

  • Leider passt dieser reguläre Ausdruck auch auf Gruppen von Großbuchstaben, die durch Leerzeilen getrennt sind. Es könnte jedoch keine große Sache sein.

    – MiniQuark

    25. Februar 09 um 20:27 Uhr

  • Sieht so aus, als ob coonj FASTA-Dateien mag. 😉

    – Andreas Dalke

    26. Februar 09 um 13:21 Uhr

.

757770cookie-checkRegulärer Ausdruck, der einem mehrzeiligen Textblock entspricht

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy