我刚问了一个关于如何check if the current line is blank or not in Perl的问题。
适用于当前行,但如何检查 next 行是否为空?
要解析的文本文件:(我需要解析文本文件并创建一个新的XML文件)
constant fixup GemEstabCommDelay = <U2 20>
vid = 6
name = "ESTABLISHCOMMUNICATIONSTIMEOUT"
units = "s"
min = <U2 0>
max = <U2 1800>
default = <U2 20>
constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG">
vid = 4
name = "" units = ""
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
我想要下面的输出。
<EquipmentConstants>
<ECID logicalName="GemEstabCommDelay " valueType="U2" value="20" vid="6" name="ESTABLISHCOMMUNICATIONSTIMEOUT" units="s" min="0" max="1800" default="20"></ECID>
<ECID logicalName="GemConstantFileName" valueType="A" value="C:\\TMP\\CONST.LOG" vid="4" name="" units=""></ECID>
<ECID logicalName="GemAlarmFileName" valueType="A" value="C:\\TMP\\ALARM.LOG" vid="0" name="" units=""></ECID>
</EquipmentConstants>
答案 0 :(得分:5)
让perl为你做。将句柄放在paragraph mode:
中$/ = ""; # paragraph mode
while (<>) {
...
}
现在在循环的每次迭代中,$_
将包含整个记录,其中每条记录由两个或多个换行符分隔。
看到它的实际效果:
#! /usr/bin/perl
use warnings;
use strict;
use 5.10.0; # for named capture buffers and %+
my $equipconst = qr/
^
constant \s+ fixup \s+ (?:private \s+)?
(?<logicalName>.+?) # non-greedy to right-trim whitespace
\s+ = \s+
< (?<valueType>\S+) \s+ (?<value>\S+) >
/x;
my $equipattr = qr/
\s*
(?<name>\S+)
\s* = \s*
(?<value>.+?) # must be non-greedy!
/x;
# read from DATA rather than standard input/named arguments
# (used for demo purposes only)
*ARGV = *DATA;
print "<EquipmentConstants>\n";
$/ = "";
while (<>) {
if (/$equipconst/g) {
my @attrs = map [ $_ => $+{$_} ] =>
qw/ logicalName valueType value /;
# \G picks up where the last //g stopped
while (/\G $equipattr (?=\s*$|$equipattr)/gx) {
my($name,$value) = @+{ qw/ name value / };
# discard tag, e.g., <U2 1800> becomes 1800
$value =~ s/<.+ (.+)>/$1/;
push @attrs => [ $name => $value ];
}
my $attrs = join " ",
map {
# strip quotes if present
$_->[1] =~ s/^"(.*)"$/$1/;
qq{$_->[0]="$_->[1]"};
}
@attrs;
print "<ECID $attrs></ECID>\n";
}
}
print "</EquipmentConstants>\n";
__DATA__
constant fixup GemEstabCommDelay = <U2 20>
vid = 6
name = "ESTABLISHCOMMUNICATIONSTIMEOUT"
units = "s"
min = <U2 0>
max = <U2 1800>
default = <U2 20>
constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG">
vid = 4
name = "" units = ""
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
输出:
<EquipmentConstants>
<ECID logicalName="GemEstabCommDelay" valueType="U2" value="20" vid="6" name="ESTABLISHCOMMUNICATIONSTIMEOUT" units="s" min="0" max="1800" default="20"></ECID>
<ECID logicalName="GemConstantFileName" valueType="A" value="C:\\TMP\\CONST.LOG" vid="4" name="" units=""></ECID>
<ECID logicalName="GemAlarmFileName" valueType="A" value="C:\\TMP\\ALARM.LOG" vid="0" name="" units=""></ECID>
</EquipmentConstants>
请注意,它与您的规范略有不同:第一个logicalName
属性不包含空格。
答案 1 :(得分:2)
使用单独的变量来存储当前行和下一行:
$_ = <>;
while ($next_line = <>) {
if ($next_line !~ /\S/) {
# do something with $_ when next line is blank
} else {
# do something else with $_ when next line is not blank
}
$_ = $next_line;
}
# $_ now contains last line of file -- you may want to do something with it here
答案 2 :(得分:1)
我不确定你想要什么,但我想你想要在每个块的最后显示具有“units = xxx”的块。如果没有,请清楚描述您的输出
$/ = "\n\n"; #set record separator
while (<>) {
chomp;
@F = split(/\n/, $_);
if ($F[-1] =~ /units/) {
print $_ ."\n";
}
}
输出
$ perl test.pl file
constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG">
vid = 4
name = "" units = ""
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
答案 3 :(得分:1)
use strict;
my @lines=<>; # slurp-in the whole file
for (my $i=0; $i<@lines-1; $i++) {
print "line " . ($i + 1) . " : next line is blank\n" if $lines[$i+1] =~ /^\s*$/;
}
答案 4 :(得分:-1)
如果您不关心内存使用情况,或者您正在阅读的文件相对较小,您只需将其全部读入数组即可。
@lines = <>;
for ($i = 0; $i < @lines; $i++)
{
print "Current line blank" if ( "" eq @lines[$i]);
print "Next line blank" if ( "" eq @lines[$i + 1]);
}