Thread Unbestimmt tiefen HashinHash erzeugen (14 answers)
Opened by scriptor at 2009-08-09 00:58

topeg
 2009-08-10 01:16
#124025 #124025
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Der Code etwas dokumentiert:
Code (perl): (dl )
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;
}


Das mit den Referenzen ist für einige nicht ganz einfach zu verstehen. Ich hoffe die Erklärung hat etwas geholfen.

View full thread Unbestimmt tiefen HashinHash erzeugen