首页 > 解决方案 > 从awk中的文件中提取前后字符到匹配的字符串

问题描述

我有一个大seq.txt的字母字符串文件,未包装,超过 200,000 个字符。没有空格、数字等,只有 az。

我有第二个文件search.txt,其中包含 50 个唯一字母的行,它们将在seq.txt. 有 4000 种模式可供匹配。

我希望能够找到每个模式(文件中的行search.txt),然后获取模式匹配之前的 100 个字符和之后的 100 个字符。

我有一个使用 grep 并且可以运行的脚本,但是它运行得很慢,只处理前 100 个字符,并且用 echo 写出。我在 awk 或 perl 方面的知识不足,无法在线解释可能适用的脚本,所以我希望这里有人!

cat search.txt | while read p; do echo "grep -zoP '.{0,100}$p' seq.txt | sed G"; done > do.grep

具有所需输出的更简单示例:

>head seq.txt    
abcdefghijklmnopqrstuvwxyz

>head search.txt
fgh
pqr
uvw

>head desiredoutput.txt
cdefghijk
mnopqrstu
rstuvwxyz

最好的结果是一个制表符分隔的文件100 characters before \t matched pattern \t 100 characters after。先感谢您!

标签: perlawkgrep

解决方案


单程

use warnings;
use strict;
use feature 'say';

my $string;

# Read submitted files line by line (or STDIN if @ARGV is empty)
while (<>) {
    chomp;
    $string = $_;    
    last;          # just in case, as we need ONE line
}
# $string = q(abcdefghijklmnopqrstuvwxyz);   # test

my $padding = 3;  # for the given test sample

my @patterns = do { 
    my $search_file = 'search.txt';
    open my $fh, '<', $search_file or die "Can't open $search_file: $!";
    <$fh>;
};
chomp @patterns;
# my @patterns = qw(bcd fgh pqr uvw);  # test

foreach my $patt (@patterns) {
    if ( $string =~ m/(.{0,$padding}) ($patt) (.{0,$padding})/x ) {
        say "$1\t$2\t$3";
        # or
        # printf "%-3s\t%3s%3s\n", $1, $2, $3;
    }
}

作为 运行program.pl seq.txt,或将其内容通过管道seq.txt传输给它。†</sup>

模式.{0,$padding}匹配任何字符._ $padding _ 3_ $patt_问题)。之后的填充也是如此。$paddingbcd$patt

在您的问题中,然后替换$padding100. 使用100每个模式之前和之后的宽“填充”,当在比 100 更接近开始的位置找到模式时\t,如果该位置小于 100 大于制表符值(通常为 8 )。

这就是带有格式化的 print ( printf) 的行的用途,以确保每个字段的宽度,而不管正在打印的字符串的长度如何。(它被注释掉,因为我们被告知没有模式进入第一个或最后 100 个字符。)

如果匹配的模式确实不可能突破第一个或最后 100 个位置,那么正则表达式可以简化为

/(.{$padding}) ($patt) (.{$padding})/x

请注意,如果 a$patt 第一个/最后一个$padding字符内,那么这将不匹配。

该程序为每个 启动正则表达式引擎,@patterns原则上可能会引发性能问题(不是一次运行少量的 4000 个模式,但这样的要求往往会发生变化并且通常会增长)。但这是迄今为止最简单的方法

  • 我们不知道模式如何在字符串中分布,并且

  • 一场比赛可能在另一场比赛的 100 字符缓冲区内(我们没有被告知其他情况)

如果此方法存在性能问题,请更新。


†</sup> 程序的输入(和输出)可以通过使用命名命令行参数以更好的方式组织,Getopt::Long例如

program.pl --sequence seq.txt --search search.txt --padding 100

其中每个参数在这里可能是可选的,在文件中设置默认值,并且参数名称可能会缩短和/或给定其他名称等。如果感兴趣,请告诉我


推荐阅读