以下代码用作最小示例。它在文本中搜索一个不匹配的正则表达式(后来是一个大的 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)
我的解决方案的问题是:
我的问题是:
正如 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...)