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

l..*_*l.. 18 regex shell perl r bioinformatics

我特别关注R,Perl和shell.但是任何其他编程语言都可以.

有没有办法以视觉或编程方式检查和索引基于正则表达式的匹配字符串?这是为了在第二个正则表达式中引用回到第一个正则表达式及其结果,以便能够修改匹配字符串的一部分并为该特定部分编写新规则.

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

问题

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

简化的例子

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

[ACGT]{1,12000}(AAC)[AG]{2,5}[ACGT]{2,5}(CTGTGTA)
Run Code Online (Sandbox Code Playgroud)

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

1. AAACCCGTGTAATAACAGACGTACTGTGTA
2. TTTTTTTGCGACCGAGAAACGGTTCTGTGTA
3. TAACAAGGACCCTGTGTA
Run Code Online (Sandbox Code Playgroud)

现在我有第二个文件,其中包含一个非常大的字符串.从第二个文件中,我只想提取那些匹配新(第二)正则表达式的子字符串,这些正则表达式本身依赖于我的第一个正则表达式.因此,第二个正则表达式必须考虑第一个文件中匹配的子字符串,并查看它们与第一个正则表达式的匹配方式!

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

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)
Run Code Online (Sandbox Code Playgroud)

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

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

在这里,rule1rule2依赖于来自第一个文件的第一个正则表达式的匹配.因此,

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)
Run Code Online (Sandbox Code Playgroud)

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

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

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

3. TAACAAGGACCCTGTGTA
Run Code Online (Sandbox Code Playgroud)

所以在这场比赛中,我们看到:

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
Run Code Online (Sandbox Code Playgroud)

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

complement means:
A will be substituted by T
T -> A
G -> C
C -> G
Run Code Online (Sandbox Code Playgroud)

所以,如果你有TAAA,补全将是ATTT.

因此,回到这个例子:

  1. TAACAAGGACCCTGTGTA

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

AAGGA has matched first.regex.p3
CC first.regex.p4
Run Code Online (Sandbox Code Playgroud)

补充是:

TTCCT (based on rule1)
GG (based on rule2)
Run Code Online (Sandbox Code Playgroud)

所以匹配second.regex的子字符串的示例是这样的:

CTAAAACACCTTTGGG TTCCT CTTAAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAG GG

这只是一个例子!但在我的情况下,我有12000个匹配的子串!! 我无法弄清楚如何解决这个问题.我曾尝试编写纯正则表达式,但我完全没有实现任何正确遵循这种逻辑的东西.也许我甚至不应该使用正则表达式?

是否可以完全使用正则表达式完成此操作?或者我应该看另一种方法?是否有可能将正则表达式和第二个正则表达式引用索引回第一个正则表达式并强制正则表达式考虑第一个正则表达式返回的匹配子串?

sim*_*que 10

这可以用Perl或任何其他语言以编程方式完成.

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

您可以逐步构建第二个模式.我在Perl中实现了一个更高级的版本,可以很容易地适应其他模式组合,而不需要改变实际工作的代码.

而不是文件1,我将使用该DATA部分.它包含所有三个示例输入字符串.而不是文件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
Run Code Online (Sandbox Code Playgroud)

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

((?^: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)
Run Code Online (Sandbox Code Playgroud)

如果您对此不熟悉,那么如果您print使用带引号的正则表达式运算符qr//构造的模式会发生这种情况.

该模式与第三种情况的示例输出相匹配.@matches2使用Data :: Printer转储时,结果如下所示.

[
    [0] "CTAAAACACCTTTGGGTTCCTCTTAAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAGGG",
    [1] "CTAAA",
    [2] "ACACC",
    [3] "TTTGGG",
    [4] "TTCCT",
    [5] "CTT",
    [6] "AAAAAAAAAGGGGGAGAGAGAAGAAAAAAAGAGAG",
    [7] "GG"
]
Run Code Online (Sandbox Code Playgroud)

我不能说这个实现的速度,但我相信它会很快合理.

如果你想找到其他模式组合,你所要做的就是替换sub { ... }这两个数组中的条目.如果第一次匹配的数量不同于其中的五个,您还将以编程方式构造该模式.我没有这样做以保持简单.这就是它的样子.

my @matches = ( $file1 =~ join q{}, map { "($_)" } @first);
Run Code Online (Sandbox Code Playgroud)

如果你想了解更多关于这种策略的信息,我建议你阅读Mark Jason Dominus的优秀高阶Perl,这里可以免费获得PDF格式.


ymb*_*rtt 1

这个问题确实让我想起了关于正则表达式的老话,尽管在这种情况下,您匹配的语言是正则的,所以 RE 很适合这个。

不幸的是,我的 Perl 有点缺乏,但从根本上来说,这听起来像是一个 Regex 问题,而不是一个 R 或 Perl 问题,所以我会在此基础上尽力回答它。

Perl 的正则表达式引擎支持捕获组。匹配正则表达式中括号内的子表达式的子字符串可以在匹配后可用:

use feature qw(say);

$foo = 'foo';
'aaa' =~ /(a)(a+)/;
say($1); # => 'a'
say($2); # => 'aa'
say("Matched!") if 'aaaa' =~ /${2}/;
Run Code Online (Sandbox Code Playgroud)

我建议做的是将你的正则表达式正确地括起来,在匹配后分开捕获组,然后将它们粘在一起形成一个新的正则表达式,比如说......

use feature qw(say);

'ACGTAACAGAGATCTGTGTA' =~ /([ACGT]{1,12000})(AAC)([AG]{2,5})([ACGT]{2,5})(CTGTGTA)/ ; # Note that I've added a lot of (s and )s here so that the results get sorted into nice groups
say($1); # => 'ACGT'
say($2); # => 'AAC'
say($3); # => 'AGAG'
say($4); # => 'AT'
say($5); # => 'CTGTGTA'

$complemented_3 = complement($3); # You can probably implement these yourself...
$complemented_4 = complement($4);

$new_regex = /${complemented_3}[ACGT]+${complemented_4}/;
Run Code Online (Sandbox Code Playgroud)

如果这些部分具有实际含义,那么我还建议查找命名捕获组,并为结果提供合适的名称而不是$1, $2, $3....

  • 我很确定如果 Damian Conway 遇到这个问题,他会写一个很长的正则表达式来解决它。:) (2认同)