我打算跳过包含“MaterialiseU4()”起始行的块内容,下面是subroutin()read_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;
}
数据如下:
__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 = ""
输出:
<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>
[更新]
我打印index($line, "MaterializeU4")
的值,输出25
。
然后我更新了以下代码
$block_started++ if ( ($line =~ /^(status)/) && (index($line, "MaterializeU4") != 25)
现在它有效。
欢迎任何评论我的做法。
答案 0 :(得分:6)
Perl已经有一个操作员来跟踪块。它被称为“触发器”操作符:
试试这个:
while ( <DATA> ) {
next if /\Q<U4 MaterializeU4()>\E/../^\s*$/;
push @lines, $_;
}
/\Q<U4 MaterializeU4()>\E/../^\s*$/
的值将为真当它看到与起始正则表达式匹配的行时,它会在看到与第二个表达式匹配的行后停止为真。
答案 1 :(得分:1)
在成功匹配子字符串时,index
返回子字符串的位置,该字符串可以是任何值&gt; = 0.在“失败”时,index
返回-1。
您使用index
index($line, "MaterializeU4") != 0
除了以字符串"MaterializeU4"
开头的行之外,对于所有行都是true。
看起来你已经对Perl正则表达式有了一些了解。为什么不在这种情况下使用一个呢?
++$block_started if $line =~ /status/ && $line =~ /MaterializeU4/;
我看到的另一个问题是你设置$block_started
来开始捕获行,但是你不会在“块”结尾处将它设置为零,比如,当$line
为空时。我不确定这是不是你想做的事。
答案 2 :(得分:1)
首先,使用正则表达式而不是索引可能更好,因为如果您可能决定更严格而不仅仅是“子串存在”,则可以将其调整为状态字符串的确切格式
我建议作为一个解决方案添加第二个标志来跳过块内容,如果它是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;
}
这是我使用codepad.org测试的略微修改的样本:
<强>代码:强>
use Data::Dumper;
my @all_lines = (
"s 1" ,"b 1" ,""
, "s MaterializeU4" ,"b 2" ,""
, "s 3" ,"b 3" ,""
);
while (@all_lines) {
my $block = read_block();
print Data::Dumper->Dump([$block]);
}
exit 0;
sub read_block {
my @lines = ();
my $block_started = 0;
my $block_ignore = 0;
while (my $line = shift @all_lines) {
if ($line =~ /^s .*?((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'
];