正则expression式匹配多行文本块
在跨越多行的文本进行匹配时,获取Python正则expression式时遇到了一些麻烦。 示例文本是('\ 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和组(2)是line1 + line2 + line3 +等,直到遇到空行。
如果有人好奇,它应该是组成蛋白质的一系列氨基酸。
尝试这个:
re.compile(r"^(.+)\n((?:\n.+)+)", re.MULTILINE)
我认为你最大的问题是,你期望^
和$
锚匹配换行,但他们不。 在多行模式下, ^
匹配紧跟在换行符后面的位置, $
与匹配换行符之前的位置匹配。
请注意换行符可以由换行符(\ n),回车符(\ r)或回车符+换行符(\ r \ n)组成。 如果您不确定您的目标文本是否仅使用换行符,则应该使用这个更具包容性的正则expression式版本:
re.compile(r"^(.+)(?:\n|\r\n?)((?:(?:\n|\r\n?).+)+)", re.MULTILINE)
顺便说一句,你不想在这里使用DOTALL修饰符; 你依靠的是点符合除了换行之外的所有事物。
这将工作:
>>> import re >>> rx_sequence=re.compile(r"^(.+?)\n\n((?:[AZ]+\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
关于这个正则expression式的一些解释可能是有用的: ^(.+?)\n\n((?:[AZ]+\n)+)
- 第一个字符(
^
)的意思是“从行首开始”。 请注意,它不符合换行符本身(与$相同,意思是“就在换行符之前”,但与换行符本身不匹配)。 - 然后
(.+?)\n\n
意思是“尽可能less地匹配字符(所有字符都是允许的),直到达到两条新行”。 结果(没有换行符)放在第一组中。 -
[AZ]+\n
表示“尽可能匹配大写字母,直到达到换行符。这定义了我将调用的文本行 。 -
((?:
textline)+)
表示匹配一个或多个文本行,但不要将每行放在一个组中。 相反,将所有的文本行放在一个组中。 - 你可以在正则expression式中添加最后一个
\n
,如果你想在最后执行一个双换行符。 - 另外,如果你不确定你会得到什么types的换行符(
\n
或\r
或\r\n
),那么只需修改正则expression式,用(?:\n|\r\n?)
。
如果每个文件只有一个氨基酸序列,我根本不会使用正则expression式。 就像这样:
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
找:
^>([^\n\r]+)[\n\r]([AZ\n\r]+)
1 = some_varying_text
\ 2 =所有CAPS的行
编辑(certificate这是有效的):
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]([AZ\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])
我的偏好。
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 )
在这一点上,你有一些变化的文字作为一个string,酸作为一个string列表。 你可以做"".join( acids )
来做一个单一的string。
我觉得这比多线正则expression式更令人沮丧(也更灵活)。