如何提取介于某个区间的几行文字,区间的开始和结束可以用正则表达式描述 。

如何提取介于某个区间的几行文字,区间的开始和结束可以用正则表达式描述 。

看了flw给出的解决方法:
这是面向行处理的一种轻量级解决方法。
比那些对整个文件进行模式匹配的方法不知优雅了要多少倍。

$start 表示开始标记的模式,$end 表示结束标记的模式,
if ( (/$start/ .. /$end/) and !/$end/ ){
表示需要开始和结束之间的,但不需要结束的那一行。

但是问题来了,若模式匹配是不严格的,即:start和end是同一性质的,如一段文字,如下:
>
reo
sot
>
tin
>12
是以开头一个>作为标志。现在要取出每一个>及其后的文字,该如何处理?另外,最后一个是例外,如何解决?大家来讨论下吧。

Hi,
there are many different way to process data. i.e.:

[Copy to clipboard] [ - ]
CODE:
use strict;
use Data::Dumper;

my $records = {};    # reference to hash
my $count = 0;       # counter for normal key record
my $key = '';        # hash key

while (<DATA>) {
    chomp;
    if (/^>(.*)/) {    # pattern match beginning with > (or followed by string)
        if ($1) {      # matsched followed by char and put it as special key
            $key = 'specialKey_'. $1;
            $records->{$key} = [];    # initial ref. array
        } else {       # put counter as key
            $key = 'count_' . ++$count;
        }
    } else {
        # put all rest blocks after line ^> into a ref. array
        push @{$records->{$key}}, $_;
    }
}
# display data structures:
print Dumper $records;

__DATA__
>
reo
sot
>
tin
>12

Output data records:

QUOTE:
$VAR1 = {
          'count_1' => [
                         'reo',
                         'sot'
                       ],
          'count_2' => [
                         'tin'
                       ],
          'specialKey_12' => []
        };

很简单
你别用那种方法就好了
土一点就是你碰到第一个
>的时候flag =1
表示进入了提取区间
然后做处理
碰到第二个>的时候flag=0,表示出了提取区间
然后碰到下一个>的时候,flag又是1
range operator 除了有两个点  ..   还有 三个点 ...


QUOTE:
原帖由 forlorngenius 于 2008-9-22 21:32 发表
range operator 除了有两个点  ..   还有 三个点 ...

呵呵。这个还没有听说过,有时间的话请详细指教。。。
另外,我已经解决了。用的笨方法。这里贴上,或许能供需要之人参考:
#!/usr/bin/perl
$file=shift;
$to_file=shift;
open(TXT, $file)  || die "can't open  $!";
open(TXT2,">$to_file") or die "error $!";
while(<TXT>){
        $content=$_;
        if(/^>\d*[\r|\n]+/){
                $_='';
                $count=1;
        }       
        if($count==1 ){
                if(/^>\d+.+\w+/){
                        $count=0;}
        }               
        if($count==1){
                $content='';}       
        print TXT2 $content;
}
close(TXT);
close(TXT2);       
提问只是简略,具体要求是:如发现一段是以>或者>\d+开头,而后面没有别的东西,则认为非法而删除。程序并不难,关键是逻辑。多谢大家的回答,希望有好的解决方法。
你确定下面的逻辑没有问题

if($count==1 ){
                if(/^>\d+.+\w+/){
                        $count=0;}
        }               
        if($count==1){
                $content='';}        
        print TXT2 $content;
应该没有,我测试了。怎么?你说说看
两个if里判断的都是 $count==1
第一个有$count=0的过程。


QUOTE:
原帖由 forlorngenius 于 2008-9-22 21:32 发表
range operator 除了有两个点  ..   还有 三个点 ...

在标量环境里,.. 返回一个布尔值。...只要它的左操作数为假就一直为假。一旦左操作数为真,该范围操作符就保持真的状态直到右操作数为真,右操作数为真之后该范围操作符再次为假。该操作符在下次计算之前不会变成假...不想拖到下一次计算中才测试右操作数..只需要用三个点(...)代替两个点(..)