awk unix - 匹配正则表达式 - 正则表达式字符串大小限制 | 想法?

Luc*_*cas 7 regex awk

以下代码用作最小示例。它在文本中搜索一个不匹配的正则表达式(后来是一个大的 DNA 文件)。

awk 'BEGIN{print match("CTGGGTCATTAAATCGTTAGC...", /.ATC|A.TC|AA.C|AAT./)}'

Run Code Online (Sandbox Code Playgroud)

后来我对找到正则表达式的位置感兴趣。因此 awk 命令更复杂。就像这里解决了一样

如果我想搜索更多的不匹配和更长的字符串,我会想出很长的正则表达式:

example: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" with 3 mismatches "." allowed:
/
...AAAAAAAAAAAAAAAAAAAAAAAAAAA|
..A.AAAAAAAAAAAAAAAAAAAAAAAAAA|
..AA.AAAAAAAAAAAAAAAAAAAAAAAAA|
-
- and so on. (actually 4060 possibilities)

/
Run Code Online (Sandbox Code Playgroud)

我的解决方案的问题是:

  • awk 不会接受很长的正则表达式!(限制似乎在大约 80.000 个字符)
  • 错误:“bash:/usr/bin/awk:参数列表太长”
  • 可能的解决方案:SO-Link但我没有找到解决方案...

我的问题是:

  • 我还能以某种方式使用长正则表达式吗?
    • 拆分字符串并多次运行命令可能是一个解决方案,但是我会得到重复的结果。
  • 有没有另一种方法来解决这个问题?
    • (“agrep”会起作用,但不能找到位置)

daw*_*awg 1

正如 Jonathan Leffler在评论中指出的那样,第一种情况 ( bash: /usr/bin/awk: Argument list too long) 中的问题来自 shell,您可以通过将 awk 脚本放入文件中来解决该问题。

正如他还指出的那样,你的基本方法并不是最佳的。以下是两种选择。


Perl 有许多功能可以帮助您完成此任务。

您可以对^两个字符串使用 XOR 运算符,这将返回\x00字符串匹配的位置和不匹配的另一个字符。将较长的字符串与较短的字符串进行异或运算,并设置最大替换数,结果如下:

use strict;
use warnings;
use 5.014;

my $seq = "CGCCCGAATCCAGAACGCATTCCCATATTTCGGGACCACTGGCCTCCACGGTACGGACGTCAATCAAAT";
my $pat     = "AAAAAA";
my $max_subs = 3;

my $len_in  = length $seq;
my $len_pat = length $pat;
my %posn;

sub strDiffMaxDelta {
    my ( $s1, $s2, $maxDelta ) = @_;
    
    # XOR the strings to find the count of differences
    my $diffCount = () = ( $s1 ^ $s2 ) =~ /[^\x00]/g;
    return $diffCount <= $maxDelta;
}

for my $i ( 0 .. $len_in - $len_pat ) { 
    my $substr = substr $seq, $i, $len_pat;
    # save position if there is a match up to $max_subs substitutions
    $posn{$i} = $substr if strDiffMaxDelta( $pat, $substr, $max_subs );
}

say "$_ => $posn{$_}" for sort { $a <=> $b } keys %posn;
Run Code Online (Sandbox Code Playgroud)

运行此打印:

6 => AATCCA
9 => CCAGAA
10 => CAGAAC
11 => AGAACG
13 => AACGCA
60 => CAATCA
61 => AATCAA
62 => ATCAAA
63 => TCAAAT
Run Code Online (Sandbox Code Playgroud)

替换:

$seq=AAATCGAAAAGCDFAAAACGT;
$pat=AATC;
$max_subs=1;
Run Code Online (Sandbox Code Playgroud)

印刷:

1 => AATC
8 => AAGC
15 => AAAC
Run Code Online (Sandbox Code Playgroud)

将其从标准输入或文件转换为“魔术输入”也很容易(与 awk 相同的风格)。


您还可以在 awk 中编写类似的方法:

echo "AAATCGAAAAGCDFAAAACGT" | awk -v mc=1 -v seq="AATC" '
{
for(i=1; i<=length($1)-length(seq)+1; i++) {
    cnt=0
    for(j=1;j<=length(seq); j++) 
        if(substr($1,i+j-1,1)!=substr(seq,j,1)) cnt++
    if (cnt<=mc) print i-1 " => " substr($1,i, length(seq)) 
    }
}'
Run Code Online (Sandbox Code Playgroud)

印刷:

1 => AATC
8 => AAGC
15 => AAAC
Run Code Online (Sandbox Code Playgroud)

与上面较长的示例的结果相同。由于输入被移至 STDIN(或文件)并且正则表达式不需要很大,因此这应该可以帮助您开始使用 Perl 或 Awk。

(请注意,字符串的第一个字符在 awk 中是偏移量 1,在 Perl 中是偏移量 0...)