正则表达式:匹配从简单字符串派生的多个模式

时间:2014-12-12 18:31:22

标签: python regex d fastq

我有以下任务: 从30个字符长的模式序列开始(它实际上是DNA序列,以免称之为P30)我需要在文本文件中找到所有以#30开头的行(^ agacatacag ...),然后是30个最后30个字符,28和最多10个字符。我需要做的就是删除模式的第一个字符并继续搜索。 为简单起见,我目前需要精确匹配,但允许更长时间(20-30个字符长的模式)的1个不匹配会更好。

我当前的,相当慢的解决方案是创建一个每行有一个截断模式的shell文件,然后grep [1]。这意味着我正在阅读巨大的,少量的GB文本文件20x,这可能需要一天+。

我可以切换到python,创建一个包含所有必需模式的列表/元组,然后只读取一次文件,每个序列循环20次,使用pypy加快速度。

  • 问题1:有没有比这种循环更快的正则表达式?
  • 问题2:通过切换到更快的编译语言来加快速度是否明智? (我想要理解Dlang)

[1]因为它是DNA序列而且要搜索的输入是FASTQ格式我使用的是fqgrep:https://github.com/indraniel/fqgrep 使用tre库:https://github.com/laurikari/tre/

edit_1 变化的例子(缩短模式)。只显示了前几步/更短的模式:

^abcde
^bcde
^cde

或者如果您更喜欢它作为DNA:

^GATACCA
^ATACCA
^TACCA

edit_2 简单的grep并没有真正削减它。我需要对每行只有第2行匹配的4行FASTQ格式进行后处理。如果我不使用fqgrep,那么我必须:

读取4行输入
  - 检查第2行(序列)是否以20种模式(P30-P10)中的任何一种开始   - 如果我得到了匹配,我需要删除第2行和第4行的前N个字符,其中N代表匹配模式的长度   - 打印输出/写入文件行#1- $ 4无匹配无效

对于内部解决方案,我可以尝试使用GNU并行分割输入文件,例如4M的谎言块,并以这种方式加快速度。但是,如果我想让其他人使用每个新软件,我要求最终用户安装广告,这是一个额外的复杂程度。

**编辑3 ** 来自Vyctor的正则表达式和匹配行的简单示例:

starting P30 regex 
^agacatacagagacatacagagacatacag
matching sequence:
^agacatacagagacatacagagacatacagGAGGACCA

P29: 
^gacatacagagacatacagagacatacag
matching sequence:
^gacatacagagacatacagagacatacagGACCACCA

P28: 
^acatacagagacatacagagacatacag
matching sequence:
^acatacagagacatacagagacatacagGATTACCA

我从左侧移除了字符/ DNA碱基(或DNA中的5-prime末端),因为这是这些序列被真实酶降解的方式。一旦找到正则表达式序列本身就没有意义。所需的输出是正则表达式之后的读取序列。在上面的例子中,它在UPERCASE中,然后可以在下一步中映射到基因组。 应该强调的是,除了这个玩具示例之外,我正在变得更长,在正则表达式之后的先验未知和变化的序列。在现实世界中,我不必处理DNA的大小写字符(一切都是大写的),但我可能会在我搜索模式的序列中遇到Ns(=未知的DNA碱基)。这些可以在第一次近似中被忽略,但是对于更敏感的算法版本,可能应该以简单的不匹配来处理。在理想情况下,不考虑给定位置的简单错配,而是计算更复杂的罚分,同时考虑以FASTQ格式存储的每4行长序列记录的第4行中存储的DNA序列质量值:http://en.wikipedia.org/wiki/FASTQ_format#Quality

但这种方式更为复杂,到目前为止,该方法仅采用与正则表达式完全匹配的读取方式。足够好,使后续步骤更容易分析。

2 个答案:

答案 0 :(得分:2)

您可以通过编程方式生成正则表达式,如下所示 它只是行开始或下一个字符的渐进式交替。

这将使您能够进行单次搜索 你所要做的就是获得比赛的字符串长度告诉你 你在哪里。

注意 - 使用多线模式。

 #  (?:^|a)(?:^|g)(?:^|a)(?:^|c)(?:^|a)(?:^|t)(?:^|a)(?:^|c)(?:^|a)(?:^|g)(?!^)0123456789

 (?: ^ | a )      # P30
 (?: ^ | g )      # P29
 (?: ^ | a )      # P28
 (?: ^ | c )      # P27
 (?: ^ | a )      # P26
 (?: ^ | t )      # P25
 (?: ^ | a )      # P24
 (?: ^ | c )      # P23
 (?: ^ | a )      # P22
 (?: ^ | g )      # P21
                  # ..
                  # P11
 (?! ^)           # Not beginning of line
 0123456789       # P10 - P1

例如,匹配这些:

agacatacag0123456789
cag0123456789
gacatacag0123456789
acatacag0123456789
acag0123456789
catacag0123456789
catacag0123456789
0123456789
atacag0123456789
tacag0123456789
ag0123456789
g0123456789

但不是这些:

agaatacag0123456789
ca0123456789
gacataca0123456789
acaacag0123456789
acg0123456789
cataca0123456789
caacag0123456789
123456789
atacg0123456789
tcag0123456789
ag012456789
g012356789

更新

这是一个图示,单个正则表达式可以替换所有30 真的不需要30个独立的正则表达式,你只需要1个常量正则表达式 在此示例中,群集组将替换为捕获组,以便您可以查看它正在执行的操作。

 # (^|G)(^|A)(^|T)(^|A)(^|C)(^|C)(?!^)A

 ( ^ | G )        # (1)
 ( ^ | A )        # (2)
 ( ^ | T )        # (3)
 ( ^ | A )        # (4)
 ( ^ | C )        # (5)
 ( ^ | C )        # (6)
 (?! ^ )          # Not beginning of line
 A

输入,6行:

GATACCA
ATACCA
TACCA
ACCA
CCA
CA

输出:

 **  Grp 0 -  ( pos 0 , len 7 ) 
GATACCA  
 **  Grp 1 -  ( pos 0 , len 1 ) 
G  
 **  Grp 2 -  ( pos 1 , len 1 ) 
A  
 **  Grp 3 -  ( pos 2 , len 1 ) 
T  
 **  Grp 4 -  ( pos 3 , len 1 ) 
A  
 **  Grp 5 -  ( pos 4 , len 1 ) 
C  
 **  Grp 6 -  ( pos 5 , len 1 ) 
C  

------------------------------

 **  Grp 0 -  ( pos 9 , len 6 ) 
ATACCA  
 **  Grp 1 -  ( pos 9 , len 0 )  EMPTY 
 **  Grp 2 -  ( pos 9 , len 1 ) 
A  
 **  Grp 3 -  ( pos 10 , len 1 ) 
T  
 **  Grp 4 -  ( pos 11 , len 1 ) 
A  
 **  Grp 5 -  ( pos 12 , len 1 ) 
C  
 **  Grp 6 -  ( pos 13 , len 1 ) 
C  

------------------------------

 **  Grp 0 -  ( pos 17 , len 5 ) 
TACCA  
 **  Grp 1 -  ( pos 17 , len 0 )  EMPTY 
 **  Grp 2 -  ( pos 17 , len 0 )  EMPTY 
 **  Grp 3 -  ( pos 17 , len 1 ) 
T  
 **  Grp 4 -  ( pos 18 , len 1 ) 
A  
 **  Grp 5 -  ( pos 19 , len 1 ) 
C  
 **  Grp 6 -  ( pos 20 , len 1 ) 
C  

------------------------------

 **  Grp 0 -  ( pos 24 , len 4 ) 
ACCA  
 **  Grp 1 -  ( pos 24 , len 0 )  EMPTY 
 **  Grp 2 -  ( pos 24 , len 0 )  EMPTY 
 **  Grp 3 -  ( pos 24 , len 0 )  EMPTY 
 **  Grp 4 -  ( pos 24 , len 1 ) 
A  
 **  Grp 5 -  ( pos 25 , len 1 ) 
C  
 **  Grp 6 -  ( pos 26 , len 1 ) 
C  

------------------------------

 **  Grp 0 -  ( pos 30 , len 3 ) 
CCA  
 **  Grp 1 -  ( pos 30 , len 0 )  EMPTY 
 **  Grp 2 -  ( pos 30 , len 0 )  EMPTY 
 **  Grp 3 -  ( pos 30 , len 0 )  EMPTY 
 **  Grp 4 -  ( pos 30 , len 0 )  EMPTY 
 **  Grp 5 -  ( pos 30 , len 1 ) 
C  
 **  Grp 6 -  ( pos 31 , len 1 ) 
C  

------------------------------

 **  Grp 0 -  ( pos 35 , len 2 ) 
CA  
 **  Grp 1 -  ( pos 35 , len 0 )  EMPTY 
 **  Grp 2 -  ( pos 35 , len 0 )  EMPTY 
 **  Grp 3 -  ( pos 35 , len 0 )  EMPTY 
 **  Grp 4 -  ( pos 35 , len 0 )  EMPTY 
 **  Grp 5 -  ( pos 35 , len 0 )  EMPTY 
 **  Grp 6 -  ( pos 35 , len 1 ) 
C  

答案 1 :(得分:2)

如果我理解正确您已预设您想要匹配:

agacatacagagacatacagagacatacag

然后匹配匹配的行:

re: agacatacagagacatacagagacatacag
30: agacatacagagacatacagagacatacag
29: agacatacagagacatacagagacatacac
28: agacatacagagacatacagagacataccc

你真的不需要regexp,你只需要找到两行之间的区别,因为它是DNA我假设字符串abcdeaebcd有4的差异,因为所有序列都需要在适当的地方。

如果订单无关紧要,并且您只想搜索至少匹配28个字符的行,则只需count differences in the strings

reg = 'agacatacagagacatacagagacatacag'
for row in file:
    letters = diff_letters(reg, row.strip())
    if letters == 30:   # complete match
    elif letters == 29: # one different character
                        # so on

如果您需要实际以正确顺序开头的匹配,则可以get points of difference between strings,如果第一个差异在点>=28

reg = 'agacatacagagacatacagagacatacag'
for row in file:
    diffs = list(i for i,(a1,a2) in enumerate(zip(s1,s2)) if a1!=a2)
    if not len(diffs):
        difference = len(reg)
    else:
        difference = diffs[0]

    if difference == 30: # First difference is at last offset