Autor Beitrag
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 07.03.09 21:18 
Hallo,

ich will in meinem Templatesytem momentan Variablen verarbeiten. Diese sind folgendermaßen aufgebaut:

ausblenden Quelltext
1:
$abc.def[$xyz.abc[$...[]]].blubb					

Sprich die Variablen fangen mit $, oder auch nicht ;), an und werden durch die Punkte genauer spezifisziert. In eckihgen Klammern stehen "Untervariablen". Zur Erklärung am besten mal, wie oberes später aussehen soll:

ausblenden Quelltext
1:
$this->var["abc"]["def"][$this->var["xyz"]["abc"][...]]["blubb"]					


Mein Problem ist jetzt: Wie überführe ich das ganze? Ich wollte es mit einem RegEx splitten, aber woran erkennt der, dass zu einem [ es die richtige ] ist, da das ganze ja rekursiv definiert ist?

Grüße
Heiko
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 08.03.09 21:28 
Inzwischen habe ich einen RegEx gebastelt, der meinen Ausdruck erkennt. Allerdings habe ich immer noch keine Idee, wie ich ihn am besten parse :(:
ausblenden C#-Quelltext
1:
(\$?\w+)(\.\w+|\[(?R)\])*					
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 08.03.09 21:40 
Das, was ein Regex nicht kann, nämlich Rekursion, musst du selbst übernehmen: Mal ein starker Pseudocode:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
method Parse(s: Stringvar currentPos: Integer) : String;
begin
  var match := Regex.Match('\$\w+(\.\w+)*\[', s.Copy(currentPos));
  currentPos += match.Length;
  Result :=
    ... // Regex-Match übersetzen
    + Parse(s, currentPos);
  if s[currentPos] <> "]" then
    Whoops!();
  Inc(currentPos);
end;

_________________
>λ=
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 08.03.09 23:32 
Stimmt so auch nicht ganz: Wenn man sich mit (?R) schon eine Rekursion schaft, muss man diese nur zusätzlich mätchen, sprich noch einmal zusätzliche Klammern drum rum. Teile in matchenden Klammern, die nicht zum Ergebnis beitragen, ergeben Leerstrings.

Deinen Ausdruck könntest Du also besser so hier schreiben:
ausblenden C#-Quelltext
1:
(\$?\w+)((?:\.\w+|\[(?R)\])*)					


In deiner Match-Gruppe 1 hast Du den Haupt-Variablen-Namen, in Gruppe 2 die gesamte Unter-Variablen-Struktur. Wichtig ist hieran anzumerken, dass man bei Wiederholungen einer Matching-Group immer nur deren letzten Match bekommt.

Das korrekte Vorgehen für deinen Fall wäre daher:
1. Mit (\$?\w+)((?:\.\w+|\[(?R)\])*) die gesamte Variable matchen
2. Aus Matching-Group 1 den Haupt-Namen auslesen.
3. Matching-Group 2 mit einem Match_all von \.\w+|\[(?R)\] in die optionalen, wiederholenden Teile aufteilen (ein preg_replace mit diesem Muster bei ersetzung durch einen Leerstring MUSS einen Leerstring liefern ;-)
4. Für jeden Teilstring prüfen, ob er mit einem . anfängt (Teil-Bezeichner), oder mit [ startet und auf ] endet. Diese weglassen (oder Match-Group auf den Content der eckigen Klammern) und diesen Teil ab Schritt 1 geschildert erneut parsen.
5. Das Ergebnis in eine brauchbare Struktur klemmen ;-)

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 08.03.09 23:53 
Meinst du nicht, dass ein preg_split da besser ist, wenn man eh alle Teile per Hand durchgehen muss?

Am Split scheitere ich aber gerade *g*:
ausblenden C#-Quelltext
1:
$match = preg_split('/((\[\$?\w*((?R)\.?\w*)*\])|\.)/''$abc.def.geh[$test][$test[df][test]][sad]', -1, PREG_SPLIT_DELIM_CAPTURE);					

ergibt:
ausblenden volle Höhe C#-Quelltext
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:
array(15) {
  [0]=>
  string(4"$abc"
  [1]=>
  string(1"."
  [2]=>
  string(3"def"
  [3]=>
  string(1"."
  [4]=>
  string(3"geh"
  [5]=>
  string(7"[$test]"
  [6]=>
  string(7"[$test]"
  [7]=>
  string(0""
  [8]=>
  string(17"[$test[df][test]]"
  [9]=>
  string(17"[$test[df][test]]"
  [10]=>
  string(6"[test]"
  [11]=>
  string(0""
  [12]=>
  string(5"[sad]"
  [13]=>
  string(5"[sad]"
  [14]=>
  string(0""
}


Mich wundern das 5 und 6 gleich sind, also ein Teil 2x erscheint :gruebel:
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Mo 06.04.09 12:48 
So, ich habs jetzt erfolgreich hinbekommen.

ausblenden C#-Quelltext
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:
<?php

function parseVarPart($match){
  if ($match[0][0]=='.'return "['".substr($match[0], 1)."']";
  return "[".parseVar(substr($match[0], 1, -1))."]";
}

function parseVar($varStr){
  preg_match('/(\$?\w+)((?:\.\w+|\[(?R)\])*)/', $varStr, $match);
  if ($match[1][0]=="$") {
    $result = '$this->vars[\''.substr($match[1], 1).'\']';
  }else{
    $result = '$this->vars[\'tplVars\'][\''.$match[1].'\']';
  }

  $result .= preg_replace_callback('/\.\w+|\[\$?\w+(?:(?R)*)\]/',
          "parseVarPart",
          $match[2]);

  return $result;
}

$str = '$abc.def.geh[$test][$test[df][$test].ijk.lmn][sad]';
if (preg_replace('/\s*\$?\w+(?:\s*(?:\.\s*\w+|\[(?R)\]))*\s*/''', $str, 1) == '') {
  $str = strtr($str, array("\t" =>"""\n" =>"""\r" =>""" " =>""));
  echo parseVar($str).';';
}else echo "Error";

?>


Irgendwelche (Performance-)Verbesserungsvorschläge?

besten dank @all
Heiko
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 06.04.09 13:31 
Würd die Syntax-Prüfung noch in ne Funktion auslagern, die dann auch gleich die Struktur der Variable liefert.

user profile iconHeiko hat folgendes geschrieben Zum zitierten Posting springen:
Irgendwelche (Performance-)Verbesserungsvorschläge?

Trace das Script doch einfach mal mit XDebug. Ein Testscript, wie man damit die Performance misst, liegt im GeSHi SVN Repo. (Damit haben Milian Wolf und ich GeSHi um das 10fache beschleunigt ;-)) ... Zur Verwendung ggf. einfach fragen.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.