Как получить значения с помощью строковых операций Perl? - PullRequest
0 голосов
/ 17 сентября 2009

У меня есть команда 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 Ответ

4 голосов
/ 17 сентября 2009

Это звучит как работа для регулярного выражения и массива хэшей .

Сначала давайте создадим шаблон, который может найти информацию. Вы ищете постоянную строку "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}. Чтобы построить массив этих записей, просто поместите запись в массив:

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/. Я склонен использовать обобщенную форму, когда растягиваю регулярное выражение на несколько строк, потому что это облегчает сопоставление начала и конца регулярного выражения в моем редакторе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...