我需要一些关于perl代码的帮助。
#!perl -w
use strict;
use warnings;
open my $file, '<', 'ubb' or die $1;
my $spool = 0;
my @matchingLines;
while (<$file>) {
if (/GROUPS/i) {
$spool = 1;
next;
}
elsif (/SERVERS/i) {
$spool = 0;
print map { "$_" } @matchingLines;
@matchingLines = ();
}
if ($spool) {
push (@matchingLines, $_);
}
}
close ($file);
该输出如下所示。
ADM LMID=GW_S4_1_PM,GW_S4_2_BM
GRPNO=1
ADM_TMS LMID=GW_S4_1_PM,GW_S4_2_BM
GRPNO=2
TMSNAME=TMS
ADM_1 LMID=GW_S4_1_PM
GRPNO=11
ADM_2 LMID=GW_S4_2_BM
GRPNO=12
DMWSG_Gateway_1 LMID=GW_S4_1_PM
GRPNO=101
ENVFILE="../GW_S4.Gateway.envfile"
DMWSG_Gateway_2 LMID=GW_S4_2_BM
GRPNO=201
ENVFILE="../GW_S4.Gateway.envfile"
DMWSG_1 LMID=GW_S4_1_PM
GRPNO=106
DMWSG_2 LMID=GW_S4_2_BM
GRPNO=206
但我只想获得每一行的第一个字(例如ADM
,ADM_TMS
,ADM_1
)。
请注意,该文件在此处打印的内容上方和下方有许多其他行。我只想对GROUPS
和SERVERS
之间的行进行此操作。
答案 0 :(得分:1)
use strict;
use warnings;
use 5.014; #say()
my $fname = 'data.txt';
open my $INFILE, '<', $fname
or die "Couldn't open $fname: $!"; #-->Not $1"
my $recording_on = 0;
my @matching_lines;
for my $line (<$INFILE>) {
if ($line =~ /groups/i) {
$recording_on = 1;
next;
}
elsif ($line =~ /servers/i) {
say for @matching_lines; #say() is the same as print(), but it adds a newline at the end
@matching_lines = ();
$recording_on = 0;
}
if ($recording_on) {
my ($first_word, $trash) = split " ", $line, 2;
push @matching_lines, $first_word;
}
}
close $INFILE;
答案 1 :(得分:1)
我建议您在代码中进行2次更改
注意:在您的问题中使用您的示例数据(以及其他内容)对其进行测试。
push
更改此
push (@matchingLines, $_);
到
push (@matchingLines, /^(\S+)/);
这会将每行的第一个单词推入数组,而不是整行。
请注意,/^(\S+)/
是$_ =~ /^(\S+)/
的简写。如果您正在使用7stud's answer中的显式循环变量,则不能使用此简写,而是使用显式语法,例如$line =~ /^(\S+)/
或循环变量。
当然,您也可以使用7stud's answer中建议的split
功能。
print
更改此
print map { "$_" } @matchingLines;
进入
local $" = "\n";
print "@matchingLines \n";
$"
指定在双引号内使用print
或say
打印数组时用于列表元素的分隔符。
或者,根据TLP's suggestion,
$\ = $/;
print for @lines;
或
print join("\n", @lines), "\n"
请注意,$/
是输入记录分隔符(默认为换行符),$\
是输出记录分隔符(默认情况下未定义)。每个$\
命令后附加print
。
有关$/
,$\
和$"
的更多信息:
perldoc -v '$/'
等即可获取这些信息。 我不认为隐式正则表达式匹配,即/pattern/
本身就不好。
但是对一个变量进行匹配,即$variable =~ /pattern/
更具可读性(因为你可以立即看到正在进行正则表达式匹配),而且更加初学者友好,但要以简洁为代价。
答案 2 :(得分:0)
您可以使用flip-flop operator (range)选择输入的一部分。这个运算符的想法是它返回false,直到它的LHS(左侧)返回true,然后它返回true直到它的RHS返回false,之后它被重置。这有点像保留一个国家。
请注意,边线也包含在匹配中,因此我们需要删除它们。之后,使用doubleDown's想法并将/^(\S+)/
推送到数组上。与push
一起使用它的好处是,如果失败,捕获正则表达式会返回一个空列表,当正则表达式不匹配时,这会给我们一个无警告的失败。
use strict;
use warnings;
my @matches;
while (<>) {
if (/GROUPS/i .. /SERVERS/i) { # flip-flop remembers the matches
next if (/GROUPS/i or /SERVERS/i);
push @matches, /^(\S+)/;
}
}
# @matches should now contain the first words of those lines