use strict; use warnings; sub dequote { my ($s) = @_; if ($s =~ /^"/) { $s =~ s/^"//; $s =~ s/"$//; } else { $s =~ s/\\([\\,])/$1/g; } return $s; } sub parse { my @terms; for ($_[0]) { my $key = /\G ( [^=,]+ ) = /xgc ? $1 : undef; my $val = /\G ( " [^"]+ " | (?: [^\\,] | \\[\\,] )* ) /xgc && dequote("$1"); push @terms, [ $key, $val ]; /\G $ /xgc and last; /\G , /xgc or die("Expected comma at pos ", pos(), "\n"); redo; } return @terms; } # --- use Data::Dumper qw( Dumper ); my $str = join ',', <<'__EOI__' =~ /.+/g; key=value\,value key=\\ key="value,value" value __EOI__ my @terms = parse($str); local $Data::Dumper::Indent = 1; local $Data::Dumper::Terse = 1; local $Data::Dumper::Useqq = 1; print(Dumper(\@terms), "\n");