my %hash; $data = "five[5]=12345&ten[10]=12345=678=90&six[6]=123456" my $reading_key = 1; my $key; my $expected_length; my $value_length; my $value; while ( $reading_key ? $data =~ /([^=]*)(=)/g : $data =~ /([^=&]*)([&=]|$)/g ) { my $chunk = $1; my $separator = $2; if ( $reading_key ) { # I expect the chunk to be complete and to # contain a number in square brackets to indicate how many # non-&/= characters the value contains. ( $key, $expected_length ) = ( $chunk =~ /^([^\[]+)\[(\d+)\]/ ); $reading_key = 0; $value = ''; $value_length = 0; } else { $value_length += length $chunk; $value .= $chunk . $separator; if ( $value_length >= $expected_length ) { $hash->{ $key } = $value; $reading_key = 1; $value = $value_length = $expected_length = undef; } } }