r - 根据返回的结果和先前正则表达式的规则创建新正则表达式|索引正则表达式并查看正则表达式如何与子字符串匹配

标签 r regex shell perl bioinformatics

我特别关注R,Perl和Shell。但是其他任何编程语言也可以。



有没有一种方法可以根据正则表达式直观地或以编程方式检查和索引匹配的字符串?这旨在参考第一个正则表达式及其在第二个正则表达式内部的结果,以便能够修改匹配字符串的一部分并为该特定部分编写新规则。

https://regex101.com确实可视化了某个字符串如何与正则表达式匹配。但这远非完美,对我的庞大数据集而言效率不高。

问题

我的第一个正则表达式有大约12000个匹配的字符串(DNA序列),我想处理这些字符串,并根据一些严格的规则在第二个文件中找到一些其他字符串,这些字符串与基于这些严格规则的12000个匹配项很好地结合在一起。

简化示例

这是我的第一个正则表达式(原始正则表达式的简化版本),贯穿我的第一个文本文件。


[ACGT]{1,12000}(AAC)[AG]{2,5}[ACGT]{2,5}(CTGTGTA)



假设它在我的大文本文件中找到以下三个子字符串:

1. AAACCCGTGTAATAACAGACGTACTGTGTA
2. TTTTTTTGCGACCGAGAAACGGTTCTGTGTA
3. TAACAAGGACCCTGTGTA


现在,我有了第二个文件,其中包含一个非常大的字符串。从第二个文件中,我只对提取与新的(第二个)正则表达式匹配的子字符串感兴趣,这些子字符串本身在几节中取决于我的第一个正则表达式。因此,第二个正则表达式必须考虑到第一个文件中匹配的子字符串,并查看它们如何与第一个正则表达式匹配!

为了简单起见,请允许我以这种方式为我的第一个正则表达式建立索引,以进行更好的说明:

first.regex.p1 = [ACGT]{1,12000}
first.regex.p2 = (AAC)
first.regex.p3 = [AG]{2,5}
first.regex.p4 = [ACGT]{2,5}
first.regex.p5 = (CTGTGTA)


现在,我的第二个(新)正则表达式将搜索第二个文本文件,并将依赖于第一个正则表达式的结果(以及从第一个文件返回的子字符串如何与第一个正则表达式匹配):


second.regex = (CTAAA)[AC]{5,100}(TTTGGG){**rule1**} (CTT)[AG]{10,5000}{**rule2**}



在这里,rule1和rule2取决于来自第一个文件上第一个正则表达式的匹配项。因此;

rule1 = look at the matched strings from file1 and complement the pattern of first.regex.p3 that is found in the matched substring from file1 (the complement should of course have the same length)
rule2 = look at the matched strings from file1 and complement the pattern of first.regex.p4 that is found in the matched substring from file1 (the complement should of course have the same length)


您可以看到第二个正则表达式具有属于其自身的部分(即,它们独立于任何其他文件/正则表达式),但它也具有取决于第一个文件的结果和第一个正则表达式的规则以及每个部分的方式的部分。第一个文件中的子字符串与第一个正则表达式匹配!

现在再次为简单起见,我使用file1中的第三个匹配子字符串(因为它比其他两个短),向您展示第二个文件中可能的匹配看起来如何以及它如何满足第二个正则表达式:

这是我们从第一个正则表达式运行到第一个文件的结果:

3. TAACAAGGACCCTGTGTA


因此,在这场比赛中,我们看到:

T has matched first.regex.p1
AAC has matched first.regex.p2
AAGGA has matched first.regex.p3
CC first.regex.p4
CTGTGTA has matched first.regex.p5


现在,在第二个文件的第二个正则表达式中,我们看到当寻找与第二个正则表达式匹配的子字符串时,我们依赖于第一个文件(与第一个正则表达式匹配)的结果。特别是,我们需要查看匹配的子字符串并补充与first.regex.p3和first.regex.p4匹配的部分(second.regex中的rule1和rule2)。

complement means:
A will be substituted by T
T -> A
G -> C
C -> G


因此,如果您有TAAA,则补充为ATTT。

因此,回到这个例子:


TAACAAGGACCCTGTGTA


我们需要补充以下内容以满足第二个正则表达式的要求:

AAGGA has matched first.regex.p3
CC first.regex.p4


补充是:

TTCCT (based on rule1)
GG (based on rule2)


因此,匹配second.regex的子字符串的示例如下:

CTAAAACACCTTTGGGTTCCTCTTAAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAGGG

这只是一个例子!但就我而言,我有12000个匹配的子字符串!我无法弄清楚如何解决这个问题。我曾经尝试编写纯正则表达式,但是我完全没有实现任何可以正确遵循此逻辑的东西。也许我甚至不应该使用正则表达式?

是否可以使用正则表达式完全做到这一点?还是我应该考虑另一种方法?是否可以索引一个正则表达式,并在第二个正则表达式引用中将其索引回第一个正则表达式,并强制该正则表达式考虑第一个正则表达式返回的匹配子字符串?

最佳答案

可以使用Perl或任何其他语言以编程方式完成此操作。

由于您需要来自两个不同文件的输入,因此无法在纯正则表达式中执行此操作,因为正则表达式无法读取文件。您甚至无法以一种模式进行操作,因为没有正则表达式引擎会记住您之前在其他输入字符串上匹配的内容。它必须在围绕您的比赛的程序中完成,这应该是正则表达式,因为正则表达式的含义是。

您可以逐步构建第二种模式。我在Perl中实现了一个更高级的版本,可以轻松地将其改编为适合其他模式组合,而无需更改实际工作的代码。

我将使用DATA部分代替文件1。它包含所有三个示例输入字符串。我将您的示例输出用于第三个输入字符串,而不是文件2。

其背后的主要思想是将两种模式都分成子模式。对于第一个,我们可以简单地使用一系列模式。对于第二个,我们创建匿名函数,并将其与第一个模式的匹配结果一起调用以构造第二个完整模式。它们中的大多数仅返回固定的字符串,但实际上有两个从参数中获取值来构建补码。

use strict;
use warnings;

sub complement {
    my $string = shift;
    $string =~ tr/ATGC/TACG/; # this is a transliteration, faster than s///
    return $string;
}

# first regex, split into sub-patterns
my @first = ( 
    qr([ACGT]{1,12000}), 
    qr(AAC), 
    qr([AG]{2,5}), 
    qr([ACGT]{2,5}), 
    qr(CTGTGTA), 
);

# second regex, split into sub-patterns as callbacks
my @second = (
    sub { return qr(CTAAA) },
    sub { return qr([AC]{5,100}) },
    sub { return qr(TTTGGG) },
    sub {
        my (@matches) = @_;

        # complement the pattern of first.regex.p3
        return complement( $matches[3] );
    },
    sub { return qr(CTT) },
    sub { return qr([AG]{10,5000}) },
    sub {
        my (@matches) = @_;

        # complement the pattern of first.regex.p4
        return complement( $matches[4] );
    },
);

my $file2 = "CTAAAACACCTTTGGGTTCCTCTTAAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAGGG";

while ( my $file1 = <DATA> ) {

    # this pattern will match the full thing in $1, and each sub-section in $2, $3, ...
    # @matches will contain (full, $2, $3, $4, $5, $6)
    my @matches = ( $file1 =~ m/(($first[0])($first[1])($first[2])($first[3])($first[4]))/g );

    # iterate the list of anonymous functions and call each of them,
    # passing in the match results of the first match
    my $pattern2 = join q{}, map { '(' . $_->(@matches) . ')' } @second;

    my @matches2 = ( $file2 =~ m/($pattern2)/ );
}

__DATA__
AAACCCGTGTAATAACAGACGTACTGTGTA
TTTTTTTGCGACCGAGAAACGGTTCTGTGTA
TAACAAGGACCCTGTGTA


这些是为您的三个输入子字符串生成的第二个模式。

((?^:CTAAA))((?^:[AC]{5,100}))((?^:TTTGGG))(TCT)((?^:CTT))((?^:[AG]{10,5000}))(GCAT)
((?^:CTAAA))((?^:[AC]{5,100}))((?^:TTTGGG))(CC)((?^:CTT))((?^:[AG]{10,5000}))(AA)
((?^:CTAAA))((?^:[AC]{5,100}))((?^:TTTGGG))(TTCCT)((?^:CTT))((?^:[AG]{10,5000}))(GG)


如果您不熟悉此方法,那么在printquoted regex operator qr//构造的模式时会发生这种情况。

该模式与您在第三种情况下的示例输出匹配。使用Data::Printer转储时得到的@matches2看起来像这样。

[
    [0] "CTAAAACACCTTTGGGTTCCTCTTAAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAGGG",
    [1] "CTAAA",
    [2] "ACACC",
    [3] "TTTGGG",
    [4] "TTCCT",
    [5] "CTT",
    [6] "AAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAG",
    [7] "GG"
]


我不能说这个实现的速度,但是我相信它会很快。

如果要查找模式的其他组合,您要做的就是替换这两个数组中的sub { ... }条目。如果第一次比赛的人数不同于五个,则您还可以通过编程方式构造该模式。为了使事情更简单,我上面没有做过。这就是它的样子。

my @matches = ( $file1 =~ join q{}, map { "($_)" } @first);




如果您想了解有关这种策略的更多信息,建议您阅读Mark Jason Dominus的出色的高阶Perl,即available for free as a PDF here

关于r - 根据返回的结果和先前正则表达式的规则创建新正则表达式|索引正则表达式并查看正则表达式如何与子字符串匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46151738/

相关文章:

r - 使用 write.table 时避免在列名和行名中使用引号

R 阅读器单 col_types

r - 按因子级别数对 R 数据框进行排序

python - 正则表达式在python中的字符串中查找两个相同的字符串

shell - AIX:使用 grep 命令记录文件中的两行

r - 无法在 R 中加载 'Caret'

java - 将正则表达式与 Kotlin 结合使用

Javascript 正则表达式与 RegExp 对象、循环内的实例

shell - 如何获取错误输出并将其存储在变量或文件中

linux - shell 脚本中的超时并报告那些超时的输入