распознавание «типа» хеш-ключей - PullRequest
5 голосов
/ 05 марта 2012

Я бы хотел использовать «скомпилированное регулярное выражение» (я имею в виду: выражение в форме qr/../) в качестве ключа для хэш-структуры.

Чтобы различать константы и эти регулярные выражения при переборе хеш-ключей, я пытался использовать ref() или is_regexp(), но первая возвращает пустую строку, а вторая не работает. Боюсь, я упускаю что-то фундаментальное из ссылок на Perl и скаляров.

Кроме того, мое решение, похоже, работает. Это слишком уродливо в любом случае? Любое альтернативное предложение приветствуется.

Некоторый код для понимания функции ref():

my $regex = qr/foo/;
printf "ref(\$regex): %s \n", ref($regex);
printf "is_regexp(\$regex): %d \n", is_regexp($regex);
# ref($regex): Regexp
# is_regexp($regex): 1

my $scalar = 3;
printf "ref(\$scalar): [%s] \n", ref($scalar);
# ref($scalar): []

my %my_hash = ('name', 'Becky', 'age', 23);
for my $k (keys %my_hash) {
    printf "%s [%s] -> %s [%s] \n", $k, ref($k), $my_hash{$k}, ref($my_hash{$k});
}
# name [] -> Becky []
# age [] -> 23 []

Ответы [ 2 ]

7 голосов
/ 05 марта 2012

Как отмечает Qtax в комментариях, хеш-ключами Perl являются всегда строки: если вы используете что-то отличное от строки в качестве хеш-ключа, оно сначала преобразуется в строку.

Вдругой комментарий, который вы пишете:

"Я читаю определения счетчиков из файла конфигурации; я хочу иметь возможность поддерживать некоторый синтаксис шаблона, например: McDouglas, McDonald, / Mc [A-Za-z] * /. Затем я читаю значения счетчиков из текстовых файлов и соответствующим образом обновляю соответствующие счетчики: McDonald 23 McIntosh 11 "

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

my @patterns = (
    'McDouglas',
    'McDonald',
    'Mc[A-Za-z]*',
);

my %regexps = map +($_ => qr/^$_$/), @patterns;
my %counters;

while (<>) {
    while (my ($pat, $re) = each %regexps) {
        $counters{$pat}++  if /$re/;
    }
}

foreach my $pat (@patterns) {
    print "$pat: ", ($counters{$pat} || 0), "\n";
}
2 голосов
/ 05 марта 2012

Что-то не так с использованием Tie::RegexpHash? Это избавляет вас от необходимости изобретать велосипед:)

use Tie::RegexpHash;

my %hash;

tie %hash, 'Tie::RegexpHash';

$hash{ qr/^5(\s+|-)?gal(\.|lons?)?/i } = '5-GAL';

$hash{'5 gal'};     # returns "5-GAL"
$hash{'5GAL'};      # returns "5-GAL"
$hash{'5  gallon'}; # also returns "5-GAL"
...