19

I'm coming to learn Perl from a Python background where the following hash-to-string conversion is built in to the language:

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> str(d)
"{'a': 1, 'c': 3, 'b': 2}"

Is there a builtin and/or module that has a subroutine with output along the lines of:

"('a' => 1, 'b' => 2, 'c' => 3)"

Strangely, a web search for perl "hash to string" doesn't turn up anything along the lines I'm looking for. Thanks!

Matthew Sainsbury
  • 1,470
  • 3
  • 18
  • 42
cdleary
  • 69,512
  • 53
  • 163
  • 191

6 Answers6

43
use Data::Dumper;
local $Data::Dumper::Terse = 1;
my $str = Dumper({a => 1, b => 2, c => 3});
Leon Timmermans
  • 30,029
  • 2
  • 61
  • 110
31

See also JSON:

#!/usr/bin/perl
use warnings; use strict;
use JSON;

my $data = {a => 1, b=> 2, c => 3};

print to_json($data);

This produces:

{"c":3,"a":1,"b":2}
dwarring
  • 4,794
  • 1
  • 26
  • 38
  • 4
    +1 While it seems Data::Dumper was voted answer, I think the JSON approach deserves as much recognition for a very simple hash to string. – Andrew T Finnell May 20 '11 at 16:36
  • 5
    Though the original question doesn't imply this is a concern, JSON::to_json is _fast_, so if you're needing to serialise a lot of things, this could be a significantly better answer than Data::Dumper. ( http://doppnet.com/2011/03/how-to-gain-24861-performance-boost-in-perl/ ) – bigiain Nov 03 '11 at 01:02
  • Thanks, I should be using JSON more anyway. Of course, on MacOS it wasn't installed, so first "cpan install JSON", thanks to https://stackoverflow.com/a/16382371/446767 – Ted Feb 27 '18 at 17:34
11

There is the Data::Dumper module which one way to do this sort of transformation.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
8

Use Data::Dump instead of Data::Dumper. It's basically the same, except without that annoying $VAR1 = ... cruft:

use Data::Dump "pp";
print pp({a => 1, b => 2, c => 3});

Produces:

{ a => 1, b => 2, c => 3 }

If you're on Windows, Data::Dump has come pre-installed with ActivePerl since version 5.8.

j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
2

Yet Another Swallow Solution:

sub pp {
  my $h = shift();
  qq[{${\(join',',map"$_=>$h->{$_}",keys%$h)}}]
}
print pp({a => 1, b => 2, c => 3});

But use Data::Dumper instead.

For very fancy output you can use also:

use Data::Dumper;
use Perl::Tidy;
sub pp {
        local $Data::Dumper::Terse    = 1;
        local $Data::Dumper::Indent   = 0;
        my $source = Dumper(@_);
        my $result;
        Perl::Tidy::perltidy(
                source      => \$source,
                destination => \$result,
                argv        => [qw(-pbp -nst)]
        );
        return $result;
}

If you prefer some keys should be first than you can use this approach (i want type first and position second):

    local $Data::Dumper::Sortkeys = sub {
            [   sort {
                            if    ( $b eq 'type' )     {1}
                            elsif ( $a eq 'type' )     {-1}
                            elsif ( $b eq 'position' ) {1}
                            elsif ( $a eq 'position' ) {-1}
                            else                       { $a cmp $b }
                            } keys %{ $_[0] }
            ];
    };
Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
2

Several of the above solutions have a problem if you have the potential for multi-level structures.

Specifically this flag:

$Data::Dumper::Terse    = 1;

As noted on the perldoc page for Data::Dumper, the "terse" flag could generate non-perl parseable output.

If you possibly are going to have multi-depth structures the proper thing to do would be to instead use:

$Data::Dumper::Indent = 0;

Which is guaranteed to be perl parseable by eval, which makes for a very very easy way of doing serialization to plaintext...

kamelkev
  • 1,136
  • 10
  • 24