Perl: Basic YAML parsing in a copy/pasteable function

I need very basic YAML parsing in Perl, mostly for reading configuration files. There aren't any great options in Perl core, and I only need a subset of YAML (basic scalars, arrays, and hashes), so I worked up a simple copy/pasteable function.

my $x = yaml_parse($yaml_str);

This implementation supports: nesting, scalars, arrays, and hashes, but is missing null / ~, booleans, and complex quotes.

sub yaml_parse {
    return {} unless defined $_[0] && length $_[0];
    my %data; my $root = \%data; my @st = ([-1, \$root]);
    for my $line (split /\n/, $_[0]) {
        $line =~ s/\r$//;
        next if $line =~ /^\s*(?:$|---\s*$|#)/;
        if ($line =~ /^(\s*)-\s*(.*)$/) {
            my ($n, $v) = (length($1), $2);
            pop @st while $n < $st[-1][0];
            my $cur = ${$st[-1][1]};
            die "yaml_parse: array without parent: $line" if @st == 1;
            $cur = ${$st[-1][1]} = [] if ref $cur eq 'HASH' && !%$cur;
            die "yaml_parse: mixed array/hash" if ref $cur ne 'ARRAY';
            $v =~ s/^\s+|\s+$//g; $v =~ s/^(['"])(.*)\1$/$2/s;
            $v += 0 if $v =~ /^-?\d+(?:\.\d+)?$/;
            push(@$cur, $v);
        } elsif ($line =~ /^(\s*)([\w\-\.\/]+)\s*:\s*(.*)$/) {
            my ($n, $key, $v) = (length($1), $2, $3);
            pop @st while $n <= $st[-1][0];
            my $cur = ${$st[-1][1]};
            die "yaml_parse: '$key' under array" if ref $cur eq 'ARRAY';
            $v =~ s/\s+$//; $v =~ s/^\s+//; $v =~ s/^(['"])(.*)\1$/$2/s;
            if ($v =~ /^\[(.*)\]$/) {
                my @a = grep { length } map { s/^\s+|\s+$//gr =~ s/^(['"])(.*)\1$/$2/sr } split /,/, $1;
                for (@a) { $_ += 0 if /^-?\d+(?:\.\d+)?$/ }
                $v = \@a;
            } else { $v += 0 if $v =~ /^-?\d+(?:\.\d+)?$/; }
            if (ref $v or length $v) { $cur->{$key} = $v }
            else { $cur->{$key} = {}; push(@st, [$n, \$cur->{$key}]) }
        } else { warn "yaml_parse: ignoring: $line\n" }
    } return \%data;
}

YAML::XS is definitely the best Perl YAML parser, but it can be overkill if all you need is simple parsing.

Tags:
All content licensed under the Creative Commons License