Mam trochę problemów z uruchomieniem wyrażenia regularnego Pythona podczas dopasowywania do tekstu obejmującego wiele wierszy. Przykładowy tekst to ('\ n' to nowa linia)
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).
Chciałbym uchwycić dwie rzeczy: część „some_Varying_TEXT” i wszystkie wiersze tekstu pisanego wielkimi literami, które pojawiają się dwa wiersze poniżej w jednym ujęciu (mogę później usunąć znaki nowej linii). Próbowałem z kilkoma podejściami:
re.compile(r"^>(\w+)$$([.$]+)^$", re.MULTILINE) # try to capture both parts
re.compile(r"(^[^>][\w\s]+)$", re.MULTILINE|re.DOTALL) # just textlines
i wiele jego odmian bez powodzenia. Ta ostatnia wydaje się dopasowywać wiersze tekstu jeden po drugim, co nie jest tym, czego naprawdę chcę. Mogę złapać pierwszą część, nie ma problemu, ale nie mogę wyłapać 4-5 wierszy tekstu pisanego wielkimi literami. Chciałbym, aby match.group (1) był jakimś_Zmienny_Tekst, a grupa (2) była linią1 + linią2 + linią3 + itd. Aż do napotkania pustej linii.
Jeśli ktoś jest ciekawy, przypuszczalnie jest to sekwencja aminokwasów tworzących białko.
>
znaku wiodącego . Czy powinno?Odpowiedzi:
Spróbuj tego:
Myślę, że Twoim największym problemem jest to, że oczekujesz, że kotwice
^
i$
będą pasować do wysuwów linii, ale tak się nie dzieje. W trybie multilinii^
dopasowuje pozycję bezpośrednio po nowej linii i$
pozycję bezpośrednio poprzedzającą nową linię.Należy również pamiętać, że znak nowej linii może składać się z wysuwu wiersza (\ n), powrotu karetki (\ r) lub powrotu karetki + wysuwu wiersza (\ r \ n). Jeśli nie masz pewności, że tekst docelowy używa tylko wysunięć wiersza, powinieneś użyć tej bardziej kompleksowej wersji wyrażenia regularnego:
BTW, nie chcesz tutaj używać modyfikatora DOTALL; polegasz na fakcie, że kropka pasuje do wszystkiego oprócz znaków nowej linii.
źródło
To zadziała:
Przydatne może być wyjaśnienie tego wyrażenia regularnego:
^(.+?)\n\n((?:[A-Z]+\n)+)
^
) oznacza „zaczynając od początku wiersza”. Należy pamiętać, że nie pasuje do samego znaku nowej linii (tak samo dla $: oznacza to „tuż przed nową linią”, ale nie pasuje do samego znaku nowej linii).(.+?)\n\n
oznacza „pasuje jak kilka znaków, jak to możliwe (wszystkie znaki są dozwolone) aż dwie nowe linie”. Wynik (bez nowych linii) jest umieszczany w pierwszej grupie.[A-Z]+\n
oznacza „dopasuj jak najwięcej wielkich liter, aż dojdziesz do nowej linii. To definiuje, co nazywam linią tekstową .((?:
textline)+)
oznacza dopasowywanie jednej lub więcej linii tekstu, ale nie umieszczaj każdej linii w grupie. Zamiast umieścić wszystkie te TextLine w jednej grupie.\n
końcówkę w wyrażeniu regularnym, jeśli chcesz wymusić podwójny znak nowej linii na końcu.\n
lub\r
lub\r\n
), po prostu popraw wyrażenie regularne, zastępując każde wystąpienie\n
przez(?:\n|\r\n?)
.źródło
Gdyby każdy plik miał tylko jedną sekwencję aminokwasów, w ogóle nie używałbym wyrażeń regularnych. Po prostu coś takiego:
źródło
odnaleźć:
\ 1 = jakiś_mienny_tekst
\ 2 = wiersze wszystkich WIELKICH LITER
Edytuj (dowód, że to działa):
źródło
Poniżej znajduje się wyrażenie regularne pasujące do wielowierszowego bloku tekstu:
źródło
Moja preferencja.
W tym momencie masz someVaryingText jako łańcuch, a kwasy jako listę łańcuchów. Możesz to zrobić
"".join( acids )
pojedynczy ciąg.Uważam to za mniej frustrujące (i bardziej elastyczne) niż wyrażenia regularne wielowierszowe.
źródło