Как я могу отредактировать некоторые значения в дампе Perl га sh? - PullRequest
0 голосов
/ 02 марта 2020

предполагается, что у меня есть эти хэши:

my $hash1 = {
  firstname => 'john',
  lastname => 'doe',
};

my $hash2_nested = {
  name => {
    firstname => 'jean',
    lastname => 'doe',
  }
};

Примечание: хэши могут быть вложены x раз глубоко.

Я хочу использовать Data :: Dumper, где я могу распечатать копию этих хэши, но со скрытой фамилией. значит, он должен распечатать:

$VAR1 = {
           'firstname' => 'john'
           'lastname' => '***',
        };
and this:
$VAR1 = {
          'name' => {
                      'firstname' => 'john'
                      'lastname' => '***',
                    }
        };

существует ли библиотека Perl, где он рекурсивно ищет ключ ha sh и динамически заменяет его значение? что-то вроде:

replace_hash_value($hash1, 'lastname', '***');

Ответы [ 2 ]

1 голос
/ 02 марта 2020

Здесь нужно рассмотреть несколько вещей. В основном, вы не хотите заново изобретать то, что уже есть. Также помните, что любая Персональная Идентификационная Информация (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 настолько гибко, насколько вам хочется, и довольно просто.

0 голосов
/ 02 марта 2020

Почему бы не написать такую ​​подпрограмму самостоятельно?

use strict;
use warnings;
use feature 'say';

my $hash1 = {
    firstname => 'john',
    lastname => 'doe'
};

my $hash2_nested = {
    name => {
        firstname => 'jean',
        lastname => 'doe'
    }
};

my $mask = 'lastname';

hash_mask($hash1,$mask);
hash_mask($hash2_nested,$mask);

sub hash_mask {
    say "\$VAR = {";
    hash_mask_x(shift, shift, 1);
    say "};";
}

sub hash_mask_x {
    my $hash   = shift;
    my $mask_k = shift;
    my $depth  = shift;

    my $indent = ' ' x 8;
    my $space  = $indent x $depth;

    while( my($k,$v) = each %{$hash} ) {
        if (ref $v eq 'HASH') {
            say $space . "$k => {";
            hash_mask_x($v,$mask_k,$depth+1);
            say $space . "}";
        } elsif( $k eq $mask_k ) {
            say $space . "'$k' => '*****'";
        } else {
            say $space . "'$k' => '$v'";
        }
    }
}

Вывод

$VAR = {
        'lastname' => '*****'
        'firstname' => 'john'
};
$VAR = {
        name => {
                'lastname' => '*****'
                'firstname' => 'jean'
        }
};
...