Leser: 28
$resulthash{'nur'}{'ein'}{'test'}{'mit'}{'zahl'}[123]=456
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#! /usr/bin/perl5.8.8 use strict; use warnings; use diagnostics; use Data::Dumper; sub QueryToHash { my $query = shift ; # der string mit der Query my %resulthash; my @parameter_arr = split /\&/, $query ; foreach my $parameter (@parameter_arr) { my $iref = \%resulthash; my ( $p_name, $p_value ) = split /=/, $parameter ; my @komponenten = split /_/, $p_name ; # zerlege name in komponenten while( my $komponente = shift @komponenten ) { if( $komponente =~ /(\d{1,6})/ ) # komponente ist dezimal { $komponente = scalar $komponente; $iref = $iref->[ $komponente ]; # ??? } else { $iref = $iref->{ $komponente }; # ??? } } $iref = $p_value; # ??? } return \%resulthash; } print Dumper( QueryToHash('test_hallo=nix&nur_ein_test_mit_zahl_123=456') ); 1;
$hash = $hash->{$el} ||= {};
2009-08-08T23:58:30 scriptorCode (perl): (dl )$hash = $hash->{$el} ||= {};
@$ref
1 2 3 4 5 6 7 8 9 10 11
sub hash { my ($ref, $hash) = @_; for my $el (@$ref) { $hash = $hash->{$el} ||= {}; } } my $h = {}; my @array = qw/ a b c d e /; hash( \@array, $h); print Dumper( $h );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
sub QueryToHash { my $query = shift ; # der string mit der Query my %resulthash; my @parameter_arr = split /\&/, $query ; foreach my $parameter (@parameter_arr) { my $iref = \%resulthash; my ( $p_name, $p_value ) = split /=/, $parameter ; my @komponenten = split /_/, $p_name ; # zerlege name in komponenten while( my $komponente = shift @komponenten ) { if( $komponente =~ /(\d{1,6})/ ) # komponente ist dezimal { # ??????????????????????????? $komponente = scalar $komponente; # $iref->[ $komponente ] = [] unless $iref->[ $komponente ]; # $iref = $iref->[ $komponente ]; } else { unless( $iref->{$komponente} ) { unless( scalar @komponenten ) { $iref->{$komponente} = $p_value ; #next; } else { $iref->{$komponente} = {} ; } } $iref = $iref->{$komponente}; } } } return \%resulthash; } print Dumper( QueryToHash('nur_ein_test_mit_zahl_123=456&nur_ein_test_ohne_zahl=789') );
1
2
3
4
5
6
7
8
9
10
11
$iref = {
'nur' => {
'ein' => {
'test' => {
'ohne' => {
'zahl' => '789'
},
'mit' => {
'zahl' => {
'123' => '456'
}}}}}};
1
2
3
4
5
6
7
8
9
10
$iref = {
'nur' => {
'ein' => {
'test' => {
'ohne' => {
'zahl' => '789'
},
'mit' => {
'zahl' => [123] = '456'
}}}}}};
1
2
3
4
$iref = { 'nur' => { 'ein' => { 'test' => {
'ohne' => { 'zahl' => '789' },
'mit' => { 'zahl' => [ undef, ..., 456] } # 456 ist 124. Eintrag
}}}}};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; sub QueryToHash { my $query = shift ; # der string mit der Query my $resulthash={}; my @parameter_arr = split /\&/, $query ; foreach my $parameter (@parameter_arr) { my ( $p_name, $p_value ) = split /=/, $parameter ; my $error=set_value($resulthash,[split('_',$p_name)],$p_value); die $error if($error); } return $resulthash; } sub set_value { my $ref=shift; my $query=shift; my $val=shift; # understandable errormessage my @path; while(@$query) { my $key=shift(@$query); my $ref_type=ref_type($ref); my $key_type=key_type($key); if($ref_type eq $key_type) { my $nkey_type=key_type($query->[0]); if($nkey_type) { my $nref=($ref_type eq 'HASH')? $ref->{$key}: $ref->[$key]; my $nref_type=ref_type($nref); if($nref_type) { $ref=$nref; } else { # no ref to hash or array # create ref if($ref_type eq 'HASH') { $ref->{$key}=($nkey_type eq 'HASH')?{}:[]; $ref=$ref->{$key}; } else { $ref->[$key]=($nkey_type eq 'HASH')?{}:[]; $ref=$ref->[$key]; } } } else { # @$query empty # set val; if($ref_type eq 'HASH') { $ref->{$key}=$val; } else { $ref->[$key]=$val; } } } else { # ERROR return "Type dismatch ref=$ref_type <=> key=$key_type in ".join('_',@path)." ($key)"; } push(@path,$key); } return 0; } sub ref_type { my $ref=shift; return undef if(!defined($ref)); return 'HASH' if(ref($ref) eq 'HASH'); return 'ARRAY' if(ref($ref) eq 'ARRAY'); return undef; } sub key_type { my $key=shift; return undef if(!defined($key)); return $key=~/^\d+$/?'ARRAY':'HASH'; } print Dumper( QueryToHash('nur_ein_test_mit_zahl_123=456&nur_ein_test_ohne_zahl=789') );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $q = 'ein_test_mit_zahl_123=456&ein_test_ohne_zahl=789'; # dies würde einen fehler erzeugen: #$q .= '&ein_test=10'; print Dumper(resolve($q)), "\n"; sub resolve { my( $query ) = @_; my $res = my $tmp = undef; for ( split /\&/, $query ) { my( $path, $val ) = split /\=/; for ( split /\_/, $path ) { if ( /^\d+$/ ) { $$res = [] if ! defined $res; $tmp = $res if ! defined $tmp; $res = \$$res->[$_]; } # if else { $$res = {} if ! defined $res; $tmp = $res if ! defined $tmp; $res = \$$res->{$_}; } # else } # for if ( ref $$res ) { die "Incorrect query!\n'$path' points to a location that already holds data.\n"; } # if else { $$res = $val; } # else $res = $tmp; } #for return $$res; } # resolve
Quote* Hast du ein Beispiel für einen 'Type dismatch', ich verstehe nicht so recht, wie es dazu kommen kann.
Quote* Wenn man an deinen Beispielstring ein '&nur_ein_test=10' anhängt, wird die Struktur zerstört.
1 2
if(ref_type(($ref_type eq 'HASH')? $ref->{$key}: $ref->[$key])) { return "Can't replace Reference by Value in ".join('_',@path)." ($key)"; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
sub QueryToHash { my $query = shift ; # der string mit der Query my $result; $result={}; for my $parameter (split(/\&/, $query)) { my ( $p_name, $p_value ) = split(/=/, $parameter,2); my $error=set_value($result,[split(/_/,$p_name)],$p_value); warn $error if($error); } return $result; } sub set_value { my $ref=shift; my $res=\$ref; my $query=shift; my $val=shift; my @path; for my $key ( @$query ) { push(@path,$key); if ( $key=~/^\d+$/ ) { if(ref($$res) && ref($$res) ne 'ARRAY') { return "Incorrect query! last key of '".join('_',@path)."' not same type as in tree\n"; } $res = \$$res->[$key]; } else { if(ref($$res) && ref($$res) ne 'HASH') { return "Incorrect query! last key of '".join('_',@path)."' not same type as in refernce\n"; } $res = \$$res->{$key}; } } if ( ref $$res ) { return "Incorrect query! '".join('_',@path)."' points to a location that already holds data.\n"; } else { $$res = $val; } return 0; }
print Dumper( QueryToHash('artikel_0_atog_mod_1_hour=14&artikel_0_atog_mod_1_min=20&artikel_0_atog_status_1=edit') );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
$VAR1 = { 'artikel' => [ { 'atog' => { 'status' => [ undef, 'edit' ], 'mod' => [ undef, { 'hour' => '14', 'min' => '20' } ] } } ] };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
sub QueryToHash { # der String mit der Querry my $query = shift ; # durch das sofortige setzen einer Hash-Referenz # erzwingen wir das alle Pfade mit einem Hash-Schlüssel beginnen müssen # sonst gibt es einen Fehler. my $result={}; # splitten nach "&" for my $parameter (split(/\&/, $query)) { # splitten nach dem ersten vorkommenden "=" # das "2" sagt nur in zwei Teile splitten my ( $p_name, $p_value ) = split(/=/, $parameter,2); # Das setzen des wertes # splitten von Pfadname an "_" # und in eine Array Referenz packen. my $error=set_value($result,[split(/_/,$p_name)],$p_value); # wenn der Rückgabewert definiert und !=0 # dann haben wir einen Fehler warn $error if($error); } return $result; } sub set_value { my $ref=shift; # "zaubern" mit Zeigern: my $res=\$ref; # Hier wird der Zeiger auf den Speicherpunkt eines Zeigers, # der auf den Anonymen Hash in "$result" verweist, erzeugt # Das löst folgendes Problem: # Nehmen mir mal an wir haben ein Hash und übernehmen einen Wert daraus: # %hash # $val=$hash{test}; # wollen wir den wert in %hash ändern müssen wir # $hash{test}=$val; # nutzen, das macht aber bei Referenzen Probleme: # $ref=\%hash # $ref=$ref->{test}; # hier können wir nicht schreiben: # $ref=$val; # und damit den wert in $ref->{test} (bzw. $hash{test}) ändern, # da wir den wert ausgelesen # und keine Referenz auf $ref->{test} erzeugt haben. # # wir brauchen also die Referenz auf $hash{test} # (beziehungsweise eine Referenz auf $ref->{test}): # $ref=\%hash; # $refref=\$ref->{test}; # (\$hash{test} ginge auch) # so haben wir die Referenz auf $ref->{test} ($hash{test}) # und nicht mehr den Wert in $ref->{test} # Nun können wir mittels # $$refref=$val; # den wert in $hash{test} ändern. # anonymes Array my $query=shift; # Wert der gesetzt werden soll my $val=shift; # dient zur besseren Ausgabe von Fehlern # zeigt den "Ort" im "Baum" wo der Fehler aufgetreten ist. my @path; # Alle Schüssel abarbeiten for my $key ( @$query ) { # den aktuellen Schlüssel zum Pfad push(@path,$key); # Wenn der Schlüssel eine Zahl ist, # dann muss es ein Array sein, # was gesucht wird. if ( $key=~/^\d+$/ ) { # Wenn es eine Referenz ist (und nicht undef) # und wenn die Referenz kein Array ist # Dann haben wir einen Fehler if(ref($$res) && ref($$res) ne 'ARRAY') { return "Incorrect query! last key of '".join('_',@path)."' not same type as in tree\n"; } # merke wenn der Wert "undef" ist, # wird automatisch der gewünschte Variablentyp erzeugt # hier ein Array-Referenz $res = \$$res->[$key]; } else { # wie oben wird geprüft, ob alles korrekt ist, # nur diesmal ob es eine Hash-Referenz ist if(ref($$res) && ref($$res) ne 'HASH') { return "Incorrect query! last key of '".join('_',@path)."' not same type as in refernce\n"; } # wieder schreiben # auch hier wird der gewünschte Typ automatisch erzeugt, # wenn er nicht vorhanden ist. # diesmal eine Hash-Referenz $res = \$$res->{$key}; } } # wenn der hier eine Referenz enthalten ist, # dann stimmt irgend was nicht. # also Abbruch if ( ref $$res ) { return "Incorrect query! '".join('_',@path)."' points to a location that already holds data.\n"; } else { # Wert setzen $$res = $val; } # alles gut gegangen return 0; }
2009-08-09T20:10:37 topegQuote* Hast du ein Beispiel für einen 'Type dismatch', ich verstehe nicht so recht, wie es dazu kommen kann.
Wenn der Schlüssel (bei mir "$key", bei dir "$_") von einem anderen Typ ('HASH' oder 'ARRAY') ist als die Refenz (bei mir "$ref" bei dir "$$res").
Ich halte es für wichtig, das ab zu fangen ohne eine InterpreterWarnung zu provozieren.