在解析文件中的正则表达式匹配时处理换行符

时间:2015-12-04 13:15:49

标签: regex perl

我有一个用换行符格式化的文件,我需要计算正则表达式的匹配项。问题是读取和测试文件的每一行,我都会丢失行之间的所有匹配

while ($row = <$fh>) {
  if ( $row =~ regexp ) {
     #do stuff

示例文件

匹配字符串:rogerbravo

文件:

alphalphaspamrogerbravo --> match ok.
alphaalphaspamspamroger --> occurrence lost
bravospamspamspamspamro --> lost
gerbravospamsspamspamsp

我想知道是否有一个优雅的解决方案,仍然一次读一行,因为该文件是一个5GB的文本文件。

由于

编辑: 正则表达式是这样的形式:/(.+?)([ATG] [TC] A。[TCG] [AG] AT [CT] [标签] / /

2 个答案:

答案 0 :(得分:1)

我能想到的显而易见的答案 - 基于你到目前为止所给出的内容 - 为什么不将你的记录分隔符设置为x

e.g。

rogerbravo

因为那时你的while循环会在每次击中时触发,local $/ = 'rogerbravo'; 将是出现次数。不幸的是,这样做的一个限制是$.不支持正则表达式 - $/rogerbravo不一样。所以它可能无法工作,因为嵌入了换行问题 - 你实际上有一堆你试图匹配的不同模式。

否则你可能不得不做一个“滚动块”的方法拼接线:

roger\nbravo

无论如何都是这样的。 (对不起,还没有真正测试过,我真的没有足够的样本数据 - 可能需要一些验证才能确保它不是双重计数)

通过将 my $prev_line = ''; my $prev_count = 0; while ( my $line = <$input_fh> ) { chomp ( $line ); my $count = $prev_line.$line =~ m/rogerbravo/g; $total += $count - $prev_count; $prev_count = $line =~ m/rogerbravo/g; #just instances in _this_ line #to exclude from next iteration. $prev_line = $line; } 设置为对数值的引用,您可以执行与设置read-by-bytes类似的操作:

$/

如果您的模式足够小,您只需要查看边界区域以查看最后几个字节是否包含模式的开头。

E.g。

local $/ = \2048; 

答案 1 :(得分:1)

更新

这是一个成对搜索行的版本。在每次传递结束时,它会删除最后一次出现的模式(如果找到),或者直到两行中第一行的末尾(如果没有),然后从文件中追加一行。这样,数据缓冲区永远不会包含两行以上的数据

还有一个小的附带条件,即此方法会错过在三个行中分割的模式的出现,例如

rog
erb
ravo

但我认为这是不可能的

use strict;
use warnings 'all';

my $count = 0;
my $pattern = 'rogerbravo';

chomp(my $data = <DATA>);

while ( <DATA> ) {
    chomp;
    my $split = length $data;
    $data .= $_;
    printf "Data buffer %d characters\n", length $data;

    while ( $data =~ /$pattern/g ) {
        ++$count;
        $split = $+[0];
    }

    $data = substr $data, $split;
}


printf qq{%d occurrences of "%s"\n}, $count, $pattern;

__DATA__
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
alphalphaspamrogerbravo
alphaalphaspamspamroger
bravospamspamspamspamro
gerbravospamsspamspamsp
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvw

输出

Data buffer 46 characters
Data buffer 46 characters
Data buffer 46 characters
Data buffer 23 characters
Data buffer 46 characters
Data buffer 41 characters
Data buffer 38 characters
Data buffer 46 characters
Data buffer 46 characters
3 occurrences of "rogerbravo"


原始解决方案

如果你保留一个数据缓冲区并一次向它添加一行,然后删除每次出现的模式字符,那么你的内存使用量将保持很小

只要存在足够的模式以保持缓冲区小

,这将正常工作
use strict;
use warnings 'all';
use feature 'say';

my $count = 0;
my $data = '';
my $pattern = 'rogerbravo';

while ( <DATA> ) {
    chomp;
    $data .= $_;
    ++$count while $data =~ s/.*?$pattern//g;
}


say qq{$count occurrences of "$pattern"};


__DATA__
alphalphaspamrogerbravo
alphaalphaspamspamroger
bravospamspamspamspamro
gerbravospamsspamspamsp

输出

3 occurrences of "rogerbravo"