Элегантный анализ жестких данных в Perl - PullRequest
2 голосов
/ 11 декабря 2010

Я работаю с большим набором данных, который в основном сводится к чему-то вроде этого:

my $input = q(
<foo>111</foo>
<foo>222</foo>
<foo>333</foo>
<foo></foo>
<foo>555</foo>
); # new-lines are either CR+LF, LF, or CR

Исходя из приведенного выше примера, давайте предположим, что действуют следующие ограничения:

  • Всегда будет 5 строк данных.
  • Данные в каждой строке заключены в один тег, такой как <foo>...</foo>.
  • Данные не будут содержать вложенных тегов.
  • Все строки используют один и тот же тег (например, foo) для включения своих данных.

В конечном счете, взяв вышесказанное в качестве источника данных, я хотел бы в итоге получить нечто похожее на это:

my %values = (
  one   => '111',
  two   => '222',
  three => '333',
  four  => '',
  five  => '555'
);

Это моя попытка:

my @vals = $input =~ m!<foo>(.*?)</foo>!ig;

if (scalar @vals != 5) {
  # panic
}

my %values = (
  one   => shift @vals,
  two   => shift @vals,
  three => shift @vals,
  four  => shift @vals,
  five  => shift @vals
);

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

Итак, учитывая вышеприведенные ограничения, что может быть более элегантным способом сделать это?

Ответы [ 3 ]

4 голосов
/ 11 декабря 2010

Объединение двух массивов в хеш:

my @keys = qw/one two three/;
my @values = qw/alpha beta gamma/;

my %hash; 
@hash{@keys} = @values;
3 голосов
/ 11 декабря 2010

Сначала взглянем на:

my %values = (
  one   => '111',
  two   => '222',
  three => '333',
  four  => '',
  five  => '555'
);

Эта структура данных связывает целое число с частью данных.Но уже существует встроенная структура данных, которая служит той же цели: массивы.

Итак, используйте массивы.Вместо записи $values{ one } вы должны написать $values[ 0 ], и отображение между целыми числами и значениями данных будет прозрачным.

Если ключи являются чем-то отличным от целых чисел, вы можете сделать:

use strict; use warnings;

my @keys = qw(a b c d e);

my $input = q(
<foo>111</foo>
<foo>222</foo>
<foo>333</foo>
<foo></foo>
<foo>555</foo>
); # new-lines are either CR+LF, LF, or CR

my %values;

# hash slice
@values{ @keys } = $input =~ m{ <foo> (.*?) </foo>}gix;

use YAML;
print Dump \%values;

Вывод:

---
a: 111
b: 222
c: 333
d: ''
e: 555
2 голосов
/ 11 декабря 2010

О, что-то вроде этого дает или берет?

use Number::Spell;
$input =~ s|<(?:/)?foo>||g;
my @lines = grep { $_ } split "\n", $input; # grep for blank lines
my $i = 0;
my %hash = map { spell_number($i++) => $_ } @lines;

Хм, я могу сделать это лучше.

use Number::Spell;
my $i = 0;
my %hash = map { s|<(?:/)?foo>||g; $_ ? spell_number($i++) => $_ : () } 
           split "\n", $input;

изд . ууууу, @ строки вместо $ input inna второй фрагмент. соблюдайте осторожность; Я только напечатал этот код; Я не написал модульный тест.

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