如何通过Perl字符串操作获取值?

时间:2009-09-17 18:07:58

标签: perl string

我有一个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)* 
  1. 我想知道如何存储上述3个结果(字母数字值和方案名称),并输入3个结构的数组。

  2. 我需要获得已加星标的方案(如上所示,方案1已加星标)并将其分配给全局变量。

1 个答案:

答案 0 :(得分:4)

这听起来像是regexarray 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/的广义形式。当我在多行中展开正则表达式时,我倾向于使用通用形式,因为它使我在编辑器中更容易匹配正则表达式的开头和结尾。