複数行のテキストブロックに一致する正規表現


105

複数行にわたるテキストと照合するときに、Python正規表現を機能させるのに少し問題があります。テキストの例は( '\ n'は改行です)

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).

「some_Varying_TEXT」の部分と、1回のキャプチャで2行下に来るすべての大文字のテキスト行をキャプチャします(後で改行文字を削除できます)。私はいくつかのアプローチで試しました:

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

そして、運のないこの多くのバリエーション。最後の1つはテキストの行と1つずつ一致するようですが、これは私が本当に望んでいることではありません。最初の部分は問題なく捕捉できますが、4〜5行の大文字のテキストは捕捉できません。空の行に遭遇するまで、match.group(1)をsome_Varying_Textに、group(2)をline1 + line2 + line3 + etcにしたいと思います。

好奇心が強い人は、タンパク質を構成するアミノ酸のシーケンスであると考えられます。


ファイルには、最初の行と大文字のテキスト以外に何かありますか?すべてのテキストを改行文字で分割し、最初の要素を「some_Varying_TEXT」とするのではなく、なぜ正規表現を使用するのかわかりません。
UncleZeiv 2009

2
はい、正規表現はこれには不適切なツールです。

サンプルテキストに先行>文字がありません。よろしいですか?
ミニクォーク、2009

回答:


114

これを試して:

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

あなたの最大の問題は、^$アンカーがラインフィードと一致することを期待していることですが、そうではありません。マルチモードでは、^直ちに位置に一致する次の改行をし、$直ちに位置と一致する前の改行。

また、改行はラインフィード(\ n)、キャリッジリターン(\ r)、またはキャリッジリターン+ラインフィード(\ r \ n)で構成できることにも注意してください。ターゲットテキストが改行のみを使用していることが確実でない場合は、次の正規表現のより包括的なバージョンを使用する必要があります。

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

ところで、ここではDOTALL修飾子を使いたくありません。ドットが改行以外のすべてに一致するという事実に依存しています。


この正規表現を空の2行目のテキストファイルとほぼ一致させたくない場合は、正規表現の2番目のドットを[AZ]に置き換えることができます。;-)
MiniQuark、2009

私の印象では、ターゲットファイルは空の行と空でない行の明確な(および繰り返しの)パターンに準拠しているため、[AZ]を指定する必要はありませんが、おそらく害はありません。
アランムーア

このソリューションは美しく機能しました。余談ですが、状況を十分に明確にしていないため(そしてこの返信が遅れているため)、お詫び申し上げます。ご協力いただきありがとうございます!
1

21

これは動作します:

>>> 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

この正規表現に関するいくつかの説明が役に立つかもしれません: ^(.+?)\n\n((?:[A-Z]+\n)+)

  • 最初の文字(^)は、「行の先頭から始まる」ことを意味します。改行自体とは一致しないことに注意してください($と同じ:「改行の直前」を意味しますが、改行自体とは一致しません)。
  • 次に(.+?)\n\n、「2つの改行に達するまで、可能な限り少ない文字数(すべての文字が許可されます)に一致する」を意味します。結果(改行なし)は最初のグループに入れられます。
  • [A-Z]+\n「改行に到達するまで、できるだけ多くの大文字に一致させます。これは、私がテキストラインと呼ぶものを定義します。
  • ((?:textline)+)は、1つまたは複数のテキスト行に一致するが、各行をグループに入れないことを意味します。代わりに、すべてテキスト行を1つのグループに入れてください
  • 最後\nに二重改行を強制したい場合は、正規表現にfinal を追加できます。
  • また、取得する改行のタイプ(\nまたは\ror \r\n)が不明な場合は、出現するすべてのをで置き換えることにより、正規表現を修正\nしてください(?:\n|\r\n?)

1
match()は、ターゲットテキストの最初の部分で1つの一致のみを返しますが、OPは、ファイルごとに何百もの一致があると述べています。代わりにfinditer()が欲しいと思います。
アランムーア

6

各ファイルにアミノ酸のシーケンスが1つしかない場合、正規表現はまったく使用しません。ちょうどこのようなもの:

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

間違いなく1つしかない場合は最も簡単な方法であり、さらにロジックを追加すると、さらに多くの方法でも機能します。ただし、この特定のデータセットには約885個のタンパク質が含まれており、正規表現でこれを処理できるはずだと感じました。
1

4

見つける:

^>([^\n\r]+)[\n\r]([A-Z\n\r]+)

\ 1 = some_varying_text

\ 2 =すべての大文字の行

編集(これが機能することの証明):

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])

残念ながら、この正規表現は空行で区切られた大文字のグループにも一致します。それは大したことではないかもしれません。
ミニクォーク、2009

coonjはFASTAファイルが好きなようです。;)
Andrew Dalke、

4

以下は、複数行のテキストブロックに一致する正規表現です。

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

1

私の好み。

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 )

この時点で、someVaryingTextが文字列としてあり、acidsが文字列のリストとしてあります。あなたは"".join( acids )単一の文字列を作るために行うことができます。

これは、複数行の正規表現よりもイライラが少ない(そして柔軟性がある)と思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.