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