How can I check if the following line is in Perl?

I just asked a question about how to check if the current line is empty or not in Perl .

This works for the current line, but how can I check if there is a next line?

Text file to parse: (I need to parse a text file and create a new XML file)

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 = ""  

I want it to be lower.

<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>
+3
source share
5 answers

Let perl do it for you. Put the pen in paragraph mode :

$/ = "";  # paragraph mode
while (<>) {
    ...
}

Now, at each iteration, the loop $_will contain an entire record, where each record is separated by two or more newline characters.

See in action:

#! /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 = ""

Output:

<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>

, spec: logicalName .

+5

:

$_ = <>;
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

I'm not sure what you want, but I assume that you want to display blocks that have "units = xxx" at the very end of each block. if not, clearly describe your conclusion

$/ = "\n\n"; #set record separator
while (<>) {
    chomp;
    @F = split(/\n/, $_);
    if ($F[-1] =~ /units/) {
        print $_ ."\n";
    }
}

Output

$ 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 = ""
+1
source
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*$/;
}
+1
source

If you don't like the memory usage, or the file you are reading is relatively small, you can just read it all into an array.

@lines = <>;

for ($i = 0; $i < @lines; $i++)
{
    print "Current line blank" if ( "" eq @lines[$i]);
    print "Next line blank"    if ( "" eq @lines[$i + 1]);
}
-1
source

Source: https://habr.com/ru/post/1726704/


All Articles