Здесь нужно рассмотреть несколько вещей. В основном, вы не хотите заново изобретать то, что уже есть. Также помните, что любая Персональная Идентификационная Информация (PII) в вашей программе может утекать, несмотря на все ваши усилия, но это не вопрос программирования.
Во-первых, вы не хотите работать с исходные данные, и поскольку у вас есть вложенные структуры, вы не можете просто сделать копию, потому что она копирует только верхний уровень и все еще делится ссылками на нижнем уровне:
my %copy = %original; # shallow copy!
Но основной модуль Storable может сделать глубокую копию, которая полностью отключена, новая копия, которая не имеет ссылок:
use Storable qw(dclone);
my $deep_copy = dclone $hash1;
Теперь вы можете играть с $deep_copy
без изменения $hash1
. Вы хотите найти все ключи last_name
и удалить их значение. Гриннц предложил модуль Data :: Walk (пример шаблона проектирования Visitor). Это как File :: Find для структур данных. Он будет заниматься всеми делами поиска хешей для вас. В своей подпрограмме wanted
пропустите все, что не интересно, затем измените интересующие узлы. Вы не беспокоитесь о том, как вы находите или получаете узлы:
use Data::Walk;
walk \&wanted, $deep_copy;
sub wanted {
return unless ref $_ eq ref {};
return unless exists $_->{last_name};
$_->{last_name} = '****';
}
Теперь соберите все это вместе. Вот смесь вложенных вещей, с некоторыми добавленными нечетными случаями, включая объект, который использует ха sh:
use v5.10;
use Hash::AsObject;
my $data = {
first_name => 'Amelia',
last_name => 'Camel',
friends => [
q(last_name => 'REDACTED BY POLICY'),
{
first_name => 'Camelia',
last_name => 'Butterfly',
},
{
first_name => 'Larry',
last_name => 'Llama',
associate => {
first_name => 'Vicky',
last_name => 'Vicuna',
}
},
],
name => {
first_name => 'Andy',
last_name => 'Alpaca',
},
object => bless {
first_name => 'Peter',
last_name => 'Python',
}, 'FooBar',
};
use Storable qw(dclone);
my $deep_copy = dclone( $data );
use Data::Walk;
walk \&wanted, $deep_copy;
use Data::Dumper;
say Dumper( $deep_copy );
sub wanted {
return unless ref $_ eq ref {};
return unless exists $_->{last_name};
$_->{last_name} = '****';
}
И вот вывод из Data::Dumper
(который можно предварительно преобразовать с помощью некоторых из его настроек):
$VAR1 = {
'object' => bless( {
'first_name' => 'Peter',
'last_name' => 'Python'
}, 'Hash::AsObject' ),
'first_name' => 'Amelia',
'last_name' => '****',
'friends' => [
'last_name => \'REDACTED BY POLICY\'',
{
'last_name' => '****',
'first_name' => 'Camelia'
},
{
'last_name' => '****',
'first_name' => 'Larry',
'associate' => {
'first_name' => 'Vicky',
'last_name' => '****'
}
}
],
'name' => {
'first_name' => 'Andy',
'last_name' => '****'
}
};
Обратите внимание, что он находит хэши в ссылке на массив, не касается объекта и не затрагивает литеральные данные, содержащие last_name =>
.
Если вам не нравится это поведение, вы можете изменить то, что вы делаете в wanted
, чтобы учесть, что вы хотели бы, чтобы произошло. Предположим, вы хотите посмотреть и на некоторые объекты, например, Ha sh :: AsObject . Один (полиморфный c) способ сделать это - найти объекты, которые позволяют вам вызывать метод last_name
(хотя это предполагает, что вы можете дать ему аргумент для изменения фамилии):
sub wanted {
if( ref $_ eq ref {} and exists $_->{last_name} ) {
$_->{last_name} = '****';
}
# merely one way to do this
elsif( eval { $_->can('last_name') } ) {
$_->last_name( '****' );
}
}
Теперь элемент last_name
в объекте также отредактирован:
$VAR1 = {
'first_name' => 'Amelia',
'friends' => [
'last_name => \'REDACTED BY POLICY\'',
{
'last_name' => '****',
'first_name' => 'Camelia'
},
{
'first_name' => 'Larry',
'associate' => {
'first_name' => 'Vicky',
'last_name' => '****'
},
'last_name' => '****'
}
],
'last_name' => '****',
'name' => {
'first_name' => 'Andy',
'last_name' => '****'
},
'object' => bless( {
'first_name' => 'Peter',
'last_name' => '****'
}, 'Hash::AsObject' )
};
Это wanted
настолько гибко, насколько вам хочется, и довольно просто.