여러 줄 텍스트 블록과 일치하는 정규식
여러 줄에 걸친 텍스트와 일치시킬 때 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'부분과 한 번의 캡처에서 두 줄 아래에 오는 모든 대문자 텍스트 줄입니다 (나중에 줄 바꿈 문자를 제거 할 수 있음). 몇 가지 접근 방식을 시도했습니다.
re.compile(r"^>(\w+)$$([.$]+)^$", re.MULTILINE) # try to capture both parts
re.compile(r"(^[^>][\w\s]+)$", re.MULTILINE|re.DOTALL) # just textlines
운없이 많은 변형이 있습니다. 마지막 하나는 텍스트 줄을 하나씩 일치시키는 것 같습니다. 첫 번째 부분은 잡을 수 있지만 문제 없습니다. 그러나 대문자 텍스트의 4-5 줄을 잡을 수없는 것 같습니다. 빈 줄이 나타날 때까지 match.group (1)을 some_Varying_Text로, group (2)를 line1 + line2 + line3 + etc로 만들고 싶습니다.
궁금한 사람이 있다면 단백질을 구성하는 일련의 아미노산이어야합니다.
이 시도:
re.compile(r"^(.+)\n((?:\n.+)+)", re.MULTILINE)
가장 큰 문제는 ^
및 $
앵커가 줄 바꿈과 일치 할 것으로 예상 하지만 그렇지 않다는 것입니다. 여러 줄 모드에서 줄 바꿈 ^
바로 뒤$
의 위치 와 줄 바꿈 바로 앞 의 위치를 찾습니다.
줄 바꿈 (\ n), 캐리지 리턴 (\ r) 또는 캐리지 리턴 + 줄 바꿈 (\ r \ n)으로 구성 될 수도 있습니다. 대상 텍스트가 줄 바꿈 만 사용하는지 확실하지 않은 경우보다 포괄적 인 정규식 버전을 사용해야합니다.
re.compile(r"^(.+)(?:\n|\r\n?)((?:(?:\n|\r\n?).+)+)", re.MULTILINE)
BTW, 여기서 DOTALL 수정자를 사용하고 싶지 않습니다. 점이 줄 바꿈을 제외한 모든 것과 일치한다는 사실에 의존 하고 있습니다.
이것은 작동합니다.
>>> 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
"두 줄 바꿈에 도달 할 때까지 가능한 한 적은 수의 문자 (모든 문자 허용) 일치"를 의미합니다. 결과 (줄 바꿈없이)는 첫 번째 그룹에 배치됩니다. [A-Z]+\n
"줄 바꿈에 도달 할 때까지 가능한 한 많은 대문자와 일치합니다. 이것은 내가 textline 이라고 부르는 것을 정의합니다 .((?:
textline)+)
means match one or more textlines but do not put each line in a group. Instead, put all the textlines in one group.- You could add a final
\n
in the regular expression if you want to enforce a double newline at the end. - Also, if you are not sure about what type of newline you will get (
\n
or\r
or\r\n
) then just fix the regular expression by replacing every occurrence of\n
by(?:\n|\r\n?)
.
If each file only has one sequence of aminoacids, I wouldn't use regular expressions at all. Just something like this:
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
find:
^>([^\n\r]+)[\n\r]([A-Z\n\r]+)
\1 = some_varying_text
\2 = lines of all CAPS
Edit (proof that this works):
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])
The following is a regular expression matching a multiline block of text:
import re
result = re.findall('(startText)(.+)((?:\n.+)+)(endText)',input)
My preference.
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 )
At this point you have someVaryingText as a string, and the acids as a list of strings. You can do "".join( acids )
to make a single string.
I find this less frustrating (and more flexible) than multiline regexes.
참고URL : https://stackoverflow.com/questions/587345/regular-expression-matching-a-multiline-block-of-text
'development' 카테고리의 다른 글
django syncdb 및 업데이트 된 모델 (0) | 2020.09.16 |
---|---|
모바일 Safari에서 클릭 이벤트에 대한 300ms 지연 제거 (0) | 2020.09.16 |
JUnit의 실패와 오류의 차이점은 무엇입니까? (0) | 2020.09.16 |
컬렉션 이니셜 라이저를 NameValueCollection과 함께 사용할 수 있습니까? (0) | 2020.09.16 |
Android XXHDPI 리소스 (0) | 2020.09.16 |