Доступ и изменение вложенного хэша на основе строки, разделенной точкой - PullRequest
0 голосов
/ 11 мая 2018

У меня есть строка ввода, скажем, apple.mango.orange = 100

У меня также есть ссылка на хеш:

$ inst = { 'банан' => 2, 'гуава' => 3, 'apple' => { 'манго' => { 'orange' => 80 } } };

Я хочу изменить значение оранжевого цвета, используя входную строку. Может кто-нибудь, пожалуйста, помогите мне, как я мог это сделать?

Я попытался разбить строку на пару (ключ, значение). Затем я сделал следующее для ключевой строки:

my $key2 = "\$inst->{".$key."}";
$key2 =~ s/\./}->{/g;
$$key2 = $value;

Это не работает, как задумано. Может ли кто-нибудь помочь мне здесь? Я прочитал FAQ Perl о том, что не следует использовать значение переменной в качестве переменной, но я не могу придумать альтернативу.

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Мало того, что символическая ссылка здесь очень плохая идея, она даже не решает вашу проблему. Вы создаете выражение в $key2, и простое засовывание еще одного знака доллара перед его именем не заставит Perl выполнить этот код. Для этого вам понадобится eval, что является еще одной плохой идеей

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

Самая большая проблема - это анализ входящей строки в списке ключей и значения. Этот код реализует подпрограмму apply, которая применяет подразумеваемую операцию в строке к вложенному хешу. Если вы не уверены в своих данных, необходимо добавить проверку ошибок, чтобы убедиться, что каждый из ключей в списке существует. Вывод Data:;Dumper предназначен только для подтверждения правильности результата

use strict;
use warnings 'all';

use Data::Dumper;

my $inst = { 'banana' => 2, 'guava' => 3, 'apple' => { 'mango' => { 'orange' => 80 } } };

my $s = 'apple.mango.orange = 100';

apply($s, $inst);

print Dumper $inst;

sub apply {
    my ($operation, $data) = @_;
    my ($keys, $val) = $operation =~ /([\w.]+)\s*=\s*(\d+)/;

    my @keys = split /\./, $keys;
    my $last = pop @keys;

    my $hash = $data;
    $hash = $hash->{$_} for @keys;
    $hash->{$last} = $val;
}

выход

$VAR1 = {
          'banana' => 2,
          'apple' => {
                       'mango' => {
                                    'orange' => '100'
                                  }
                     },
          'guava' => 3
        };
0 голосов
/ 11 мая 2018

Вы строите строку, которая состоит из (глючного) кода Perl, но вы никогда не просите Perl его выполнить. ... но это не правильный подход.

sub dive_val :lvalue {
   my $p = \shift;
   $p = \($$p->{$_}) for @_;
   $$p
}

my @key = split /\./, "apple.mango.orange";
dive_val($inst, @key) = $value;

или

use Data::Diver qw( DiveVal );

my @key = split /\./, "apple.mango.orange";
DiveVal($inst, map \$_, @key) = $value;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...