如何在阅读Perl时跳过某些块内容

如何在阅读Perl时跳过某些块内容,perl,expression,Perl,Expression,我计划跳过块内容,其中包括“MaterializeU4()”的起始行以及下面的子例程()read\u block。但失败了 # Read a constant definition block from a file handle. # void return when there is no data left in the file. # Otherwise return an array ref containing lines to in the block. sub read_

我计划跳过块内容,其中包括“MaterializeU4()”的起始行以及下面的子例程()
read\u block
。但失败了

# Read a constant definition block from a file handle. 
# void return when there is no data left in the file. 
# Otherwise return an array ref containing lines to in the block.  
sub read_block { 
    my $fh = shift; 

    my @lines; 
    my $block_started = 0; 

    while( my $line = <$fh> ) { 

    # how to correct my code below? I don't need the 2nd block content.
 $block_started++ if ( ($line =~ /^(status)/) && (index($line, "MaterializeU4") != 0) ) ;

 if( $block_started ) { 

     last if $line =~ /^\s*$/; 

     push @lines, $line; 
 }

    } 
    return \@lines if @lines;
    return; 
} 
#从文件句柄读取常量定义块。
#当文件中没有剩余数据时,返回void。
#否则,返回一个数组ref,该数组ref包含块中的行。
子读取块{
我的$fh=班次;
我的@行;
我的$block_start=0;
而(我的$line=){
#如何更正下面的代码?我不需要第二块内容。
$block_started++if($line=~/^(status)/)&&&(index($line,“MaterializeU4”)!=0);
如果($block_启动){
最后一个if$line=~/^\s*$/;
按@行,$line;
}
} 
如果@行,则返回\@行;
返回;
} 
数据如下:

__DATA__ 
status DynTest = <dynamic 100>
vid = 10002
name = "DynTest"
units   = ""

status VIDNAME9000 = <U4 MaterializeU4()>
vid = 9000
name = "VIDNAME9000"
units = "degC"

status DynTest = <U1 100>
vid = 100
name = "Hello"
units   = ""
数据
状态动态测试=
vid=10002
name=“DynTest”
units=“”
状态VIDNAME9000=
vid=9000
name=“VIDNAME9000”
单位=“degC”
状态动态测试=
vid=100
name=“你好”
units=“”
输出:

  <StatusVariables>
    <SVID logicalName="DynTest" type="L" value="100" vid="10002" name="DynTest" units=""></SVID>
    <SVID logicalName="DynTest" type="L" value="100" vid="100" name="Hello" units=""></SVID>
  </StatusVariables>

[更新] 我打印
索引($line,“MaterializeU4”)
的值,它输出
25
。 然后我更新了代码如下

$block_start++if($line=~/^(status)/)和&(index($line,“materialieu4”)!=25)

现在它起作用了


欢迎对我的做法提出任何意见。

成功匹配子字符串时,返回子字符串的位置,可以是任何值>=0。在“失败”时,
索引
返回-1

您使用索引的方式

index($line, "MaterializeU4") != 0
对于除以字符串
“MaterializeU4”
开头的行以外的所有行都将为true

看起来您对Perl正则表达式已经了解了一点,为什么不在本例中也使用一个呢

++$block_started if $line =~ /status/ && $line =~ /MaterializeU4/;

我看到的另一个问题是,您将
$block\u start
设置为开始捕获行,但从未在“block”末尾将其设置为零,例如,
$line
为空。我不确定这是否是您想要做的。

成功匹配子字符串时,返回子字符串的位置,可以是任何值>=0。在“失败”时,
索引
返回-1

您使用索引的方式

index($line, "MaterializeU4") != 0
对于除以字符串
“MaterializeU4”
开头的行以外的所有行都将为true

看起来您对Perl正则表达式已经了解了一点,为什么不在本例中也使用一个呢

++$block_started if $line =~ /status/ && $line =~ /MaterializeU4/;

我看到的另一个问题是,您将
$block\u start
设置为开始捕获行,但从未在“block”末尾将其设置为零,例如,
$line
为空。我不确定这是否是您想要做的。

首先,使用正则表达式而不是索引可能更好,因为如果您决定更严格,而不仅仅是“substring exists”,您可以将其调整为状态字符串的精确格式

我建议作为一种解决方案,添加第二个标志以跳过块内容(如果是MaterializeU4块),如下所示:

# Read a constant definition block from a file handle. 
# void return when there is no data left in the file. 
# Empty return for skippable (Materialize4U) block!!!
# Otherwise return an array ref containing lines to in the block.  
sub read_block { 
    my $fh = shift; 
    my @lines = (); 
    my $block_started = 0; 
    my $block_ignore = 0;
    while (my $line = <$fh> ) { 
        if ($line =~ /^status.*?((MaterializeU4)?)/) {
            $block_started = 1;
            $block_ignore = 1 if $1;
        }
        last if $line =~ /^\s*$/ && $block_started;
        push @lines, $line unless $block_ignore; 
    } 
    return \@lines if @lines || $block_started;
    return; 
} 
输出

$VAR1 = [
          's 1',
          'b 1'
        ];
$VAR1 = [];
$VAR1 = [
          's 3',
          'b 3'
        ];

首先,使用正则表达式而不是索引可能更好,因为如果您决定比“substring exists”更严格,您可以将其调整为状态字符串的精确格式

我建议作为一种解决方案,添加第二个标志以跳过块内容(如果是MaterializeU4块),如下所示:

# Read a constant definition block from a file handle. 
# void return when there is no data left in the file. 
# Empty return for skippable (Materialize4U) block!!!
# Otherwise return an array ref containing lines to in the block.  
sub read_block { 
    my $fh = shift; 
    my @lines = (); 
    my $block_started = 0; 
    my $block_ignore = 0;
    while (my $line = <$fh> ) { 
        if ($line =~ /^status.*?((MaterializeU4)?)/) {
            $block_started = 1;
            $block_ignore = 1 if $1;
        }
        last if $line =~ /^\s*$/ && $block_started;
        push @lines, $line unless $block_ignore; 
    } 
    return \@lines if @lines || $block_started;
    return; 
} 
输出

$VAR1 = [
          's 1',
          'b 1'
        ];
$VAR1 = [];
$VAR1 = [
          's 3',
          'b 3'
        ];

Perl已经有了一个跟踪块的操作符。它被称为“触发器”操作符:

试试这个:

while ( <DATA> ) { 
   next if /\Q<U4 MaterializeU4()>\E/../^\s*$/;
   push @lines, $_;
}
while(){
下一个if/\Q\E/./^\s*$/;
按@行,$\;
}

当看到与起始正则表达式匹配的行时,
/\Q\E/./^\s*$/
的值将为真,当它看到与第二个表达式匹配的行时,它将停止为真。

Perl已经有一个跟踪块的运算符。它被称为“触发器”运算符:

试试这个:

while ( <DATA> ) { 
   next if /\Q<U4 MaterializeU4()>\E/../^\s*$/;
   push @lines, $_;
}
while(){
下一个if/\Q\E/./^\s*$/;
按@行,$\;
}

/\Q\E/./^\s*$/
的值在看到与起始正则表达式匹配的行时将为真,在看到与第二个表达式匹配的行后将不再为真。

规则。实际上,daotoad很乐意将完整的示例代码作为另一个stackoverflow答案为我编写。它只是一个pice代码。我正在阅读和学习使用它。谢谢。规则-我认为
$block\u启动时
可以不重置,因为它定义了块范围-一旦块结束,子块将退出。如果子处理>1 block.rule,这将是一个合理的问题-另外,我想你的意思是
$line!~/materialieu4/
,不?优雅的解决方案…我的产生空块k、 而您的代码只是跳过了该块的整组行并继续执行下一个blockrule,我测试了用
if($line=~/^(status)/)和($line!~/materialieu4/)替换我原来的if条件
。它工作得很好。谢谢。规则。实际上,道蟾蜍很乐意为我写下完整的示例代码作为另一个stackoverflow答案。它只是一个pice代码。我正在阅读和学习它。谢谢。规则-我认为
$block_启动时
可以不重置,因为它定义了块的范围-一旦块被重置结束后,sub将退出。如果sub处理>1 block.rule,这将是一个合理的问题-而且,我想你的意思是
$line!~/materialeu4/
,不是吗?优雅的解决方案…我的生成空块,而你的只是跳过该块的整组行并继续下一个blockrule,我测试了用
I替换我原来的if条件f($line=~/^(status)/)&($line!~/materialieu4/);
。它工作得很好。谢谢。顺便说一句,我选择了稍微灵活一点的方法,为可跳过的块返回空数组,而不是只是默默地跳过它。对于当前的需要,这有点过分了,但Oth可以在以后扩展,以便对此类块进行其他处理