我有一个DOS命令输出如下(只是一个包含3个结果的例子):
The Scheme GUID: 123-abc (Scheme1) * The Scheme GUID: 456-def (Scheme2) The Scheme GUID: 789-ghi (Scheme3)
我从Perl脚本调用命令行程序,我想在结构中存储两个结果:
**123-abc** (alphanumeric value) & **Scheme1**(name of the scheme) *(values obtained from the results mentioned above in the eg)*
我想知道如何存储上述3个结果(字母数字值和方案名称),并输入3个结构的数组。
我需要获得已加星标的方案(如上所示,方案1已加星标)并将其分配给全局变量。
答案 0 :(得分:4)
这听起来像是regex和array of hashes的作业。
首先,让我们创建一个可以找到信息的模式。您正在寻找一个常量字符串"The Scheme GUID: "
,后跟一个连续的字母数字和连字符字符串,后跟一个空格,然后是括号括起来的连续字母数字字符串。在正则表达式中,这是/The Scheme GUID: [a-zA-Z0-9-]+ \([a-zA-Z0-9]+\)/
。现在,这只会匹配字符串,我们想要提取它的部分,所以我们需要将捕获添加到正则表达式并捕获它的返回:
my ($guid, $scheme) = /The Scheme GUID: ([a-zA-Z0-9-]+) \(([a-zA-Z0-9]+)\)/;
()
用于表示我们要从字符串中保存的部分,称为捕获。
现在我们有了这些值,你想要创建一个类似记录的结构。在Perl中,您通常会为此目的使用哈希:
my %record = (
guid => $guid,
scheme => $scheme
);
您现在可以通过说$record{guid}
来访问guid。要构建这些记录的数组,只需将记录推送到数组:
my @records;
while (<>) {
my ($guid, $scheme) = /The Scheme GUID: ([a-zA-Z0-9-]+) \(([a-zA-Z0-9])\)/;
my %record = (
guid => $guid,
scheme => $scheme
);
push @records, \%record;
}
您现在可以访问第三条记录的方案,如下所示:$records[2]{scheme}
。
您的上一个要求需要更改正则表达式。如果你看到它,你需要寻找那个明星并做一些特别的事。不幸的是,星星意味着正则表达式,所以你需要像使用括号一样逃避它。星星并不总是存在,所以你需要使用非分组括号(?:)
和?
量词来告诉正则表达式不匹配字符串的那部分是正常的:
my ($guid, $scheme, $star) = /The Scheme GUID: ([a-zA-Z0-9-]+) \(([a-zA-Z0-9]+)\)(?: (\*))?/;
正则表达式已经很长很难读,所以使用/x
标志并向正则表达式添加一些空格和注释可能是个好主意:
my ($guid, $scheme, $star) = m{
The [ ] Scheme [ ] GUID:
([a-zA-Z0-9-]+) #capture the guid
[ ]
\( ([a-zA-Z0-9]+) \) #capture the scheme
(?:
[ ]
(\*) #capture the star if it exists
)?
}x;
他们这样编写这样的程序是:
#!/usr/bin/perl
use strict;
use warnings;
my $primary_record;
my @records;
while (<DATA>) {
next unless my ($guid, $scheme, $star) = m{
The [ ] Scheme [ ] GUID: [ ]
([a-zA-Z0-9-]+) #capture the guid
[ ]
\( ([a-zA-Z0-9]+) \) #capture the scheme
(?:
[ ]
([*]) #capture the star if it exists
)?
}x;
my %record = (
guid => $guid,
scheme => $scheme,
starred => defined $star ? 1 : 0
);
if ($record{starred}) {
$primary_record = \%record;
}
push @records, \%record;
}
print "records:\n";
for my $record (@records) {
print "\tguid: $record->{guid} scheme: $record->{scheme}\n";
}
print "primary record is $primary_record->{guid}\n";
__DATA__
The Scheme GUID: 123-abc (Scheme1) *
The Scheme GUID: 456-def (Scheme2)
The Scheme GUID: 789-ghi (Scheme3)
如果您拥有数组中的数据,则可以使用while
循环替换for
循环:
for my $line (@lines) {
next unless my ($guid, $scheme, $star) = $line =~ m{
The [ ] Scheme [ ] GUID: [ ]
([a-zA-Z0-9-]+) #capture the guid
[ ]
\( ([a-zA-Z0-9]+) \) #capture the scheme
(?:
[ ]
([*]) #capture the star if it exists
)?
}x;
next unless match
成语说如果这个与正则表达式不匹配则获得不同的行。 m{regex}
是/regex/
的广义形式。当我在多行中展开正则表达式时,我倾向于使用通用形式,因为它使我在编辑器中更容易匹配正则表达式的开头和结尾。