Beat: kleiner Parser, Bewertung

Beitrag lesen

[1=...] bis [4=...] => Überschriften
[link=...] und [link=...@titel=...] => Hyperlinks einfach/komplex
[liste=...,...] => Aufzählungsliste, eine Ebene
[nliste=...,...] => Nummerierte Liste, eine Ebene
[f=...], [k=...] und [u=...] => Fett, Kursiv und unterstrichen

Erst mal meine Frage: Was haltet ihr von dieser Logik? Ist sie einprägsam, einfach zu lesen und zu erlernen? Gibt es Ecken, an denen man noch etwas verbessern kann?

Versuche nicht, die eher anonymen Elementnamen von HTML nachzuahmen

[head:]
[chapter:]
[legend:]
sind aussagekräftiger.

Mache dir in deinem Parser Gedanken zu Verschachtelung:

<
  [url:>
  [label:]
  [hreflang:]
  [rel:nofollow]
]
[img:
  [url:]
  [alt:]
  [legend:]
  [cite:]
]

Sowie der Frage, welche Optionen sind optional und welches sind Defaultwerte, bzw. wann werden sie gesetzt.

Und zum dieser Code:

... eine Liste vonn Patterns

  

> Ist der Code sehr serverlastig?  
  
Er ist unübersichtlich, und das Parsen einer Funktion ist abhängig vom bisherigen Parsen.  
[k=[f=fett und kursiv]]  
... geht, aber nicht  
[f=[k=fett und kursiv]]  
  
Ich arbeite in Perl wie folgt:  
  
# Dieses Pattern erlaubt mir, verschachtelten Code zu erkennen.  
~~~perl
my $Nested2Level = qr{  
	[^\[\]]*  
	(?:  
		\[  [^\[\]]*  
			(?:  \[  [^\[\]]*  \]  [^\[\]]*  )*  
		\]  [^\[\]]*  
	)*  
	}x;  
# Hauptparser  
# Erkennt Syntax, aber nicht dir konkrete Funktion  
sub parse_function{  
    my $t=shift || '';  
    for($t){  
        # \[ist:maskiert\] soll nicht als Funktion verstanden werden  
        # deshalb (?<!\\) \[  
        s{ (?<!\\) \[ ([a-z]+) : ($Nested2Level) (?<!\\) \] }  
         { ehf_function_dispatch( $1, $2 ) }exg;  
        s#\\\[#[#g;  # maskierungen entfernen  
        s#\\\]#]#g;  # maskierungen entfernen  
    }  
    return $t;  
}  
  
# Testet ob der Inhalt einer Syntax eine Funktion entspricht.  
sub ehf_function_dispatch{  
    exists $EhfFunction_Dispatch{$_[0]}  
         and return $EhfFunction_Dispatch{$_[0]}->($_[1]);  
    return('\\[' . $_[0] . ':' . $_[1] . '\\]');  
}  
  
# wobei alle Referenzen zu den Callbackfunktionen in eine Hash gespeichert werden:  
  
my %EhfFunction_Dispatch = (  
	get          => \&user_get,  
	footnote     => \&user_footnote,  
	link         => \&user_link,  
	mailtolink   => \&user_mailtolink,  
	mailthispage => \&user_mailthispage,  
	image        => \&user_image,  
	navigation   => \&user_navigation,  
	plugin       => \&user_plugin,  
	htmlchars    => \&user_htmlchars,  
	select       => \&user_select,  
	ml           => \&user_ml,  
	# Funktionen für Spezialseiteneinbindung  
	guestbook    => \&user_guestbook,  
	formmail     => \&user_formmail,  
	news         => \&user_news,  
	register     => \&user_register,  
	search       => \&user_search,  
);  
  
#und dann folgen die einzelnen Funktionen:  
# hier nur stellvertrentend ein:  
  
sub user_link{  
    my $t = shift;  
    my $url = my $label = '-';  
    my $rel = my $hreflang = '';  
    if( $t =~ m#((https?://[^/\s\[\]]*) (?:( / (?:[^\?\s\#\[\]]*)? ) (?:\?[^\#\s\[\]]*)? )? ) #x ){  
        $url = $1;  
        $label = $2 || '' . $3 || '';  
    }  
    elsif( $t =~ m#\[url:(.*?)\]#x ){  
        $label = $url = $1;  
    }  
    $url =~ m/^__/ and $User{status} eq 'robot' and return '';  
    if( $url and $url !~ m!^(https?:|__)! ){  
        exists $Store->{page}{$url}  
            or return('<b class=warning>ERROR: '.t('Page does not exist').'!</b>');  
        $Userlevel{ $User{status} } < $Userlevel{ $Store->{page}{$url}{status} } and  
            return('<b class=warning>'.t('Rechte nicht ausreichend').'</b>');  
    }  
    $t =~ m/\[label:(.*?)\]/ and $label = $1;  
    $t =~ m/\[menu:(.*?)\s+(.*?)\]/  
        and $label = '<var class="menu">'. $1 . '</var> &#x25b8; <var class="menu">' . $2 .'</var>';  
    $t =~ m/\[rel:([a-z\ ]+?)\]/ and $rel = ' rel="'.$1.'"';  
    $t =~ m/\[hreflang:([a-z][a-z](?:-[A-Z][A-Z])?)\]/ and $hreflang = ' hreflang="'.$1.'"';  
    return( '<a'.($hreflang ? $hreflang : '').' href="'.$url.'" title="'.$url.'"'.($rel ? $rel : '').'>'.$label.'</a>' );  
}  

Durch diese Anordnung kann ich komplexe Funktionen bereitstellen.
Funktionen können Optionen enthalten, wobei durch die Callback Funktionen sichergestellt ist, dass die Optionen keine bestimmte Reihenfolge haben müssen.
Ich habe eine einheitliche Syntax.
Das Parsen ist performant.

Wenn ich das jetzt mit deinem Konzept vergleiche:
Bei dir können Funktionen nur zufällig verschachtelt sein.
[f:] für fett entbehrt sowohl jeder Memnotik wie Konvention.
Dass du gleich inline-styles setzt, ist eine zusätzliche Sünde.
Dein Verzicht auf Callbackfunktionen wird bei Listen und Tabellen zu sehr unzuverlässigen Ergebnissen führen.

Ich halte deinen Ansatz für wenig geeignet. Die Syntax halte ich für ansatzweise geeignet, jedoch ist [1=] wirklich unter aller Sau.

Schränke deine Syntax so ein, dass sie konsistent und einfach wird.
Vermeide Fehler jetzt, bevor du sie in alle Ewigkeiten supporten musst.

mfg Beat

--
Woran ich arbeite:
X-Torah
Plädoyer für eine alte Mystik
und Vers-Einteilung
in der Torah und der Apokalypse
Beat Stoecklin 2008
><o(((°>           ><o(((°>
   <°)))o><                     ><o(((°>o
Der Valigator leibt diese Fische