V
4  
Tags
Attachments
Perl 6
Perl 6 Tutorial Part 7


Text, Rules and Grammars

Willkommen zum siebenten Teil dieses poetischen Perl 6-Tutorials, da� vor allem
den Umgang mit Text, also Strings, zum Inhalt hat. Das klingt stark nach Regex,
beinhaltet aber noch einiges mehr, wie I<quoting>, Interpolation und Formate.
Beginnen wir jedoch mit den einfachsten Grundlagen.

Es werde String

Wie im zweiten Kapitel beschrieben, ist f�r Perl 6, ebenso wie in Perl 5, String
nur ein Kontext, in den beliebige Daten umgewandelt werden k�nnen. Dieser Kontext
wird aber nicht nur mit Operatoren erzeugt die mit C<~> beginnen, sondern auch
wenn ein Text ganz einfach in Anf�hrungszeichen in den Quellcode eingef�gt wird.

Einfaches Quoting

Die schlichte Variante sind dabei (wie bekannt) die einfachen Anf�hrungszeichen,
innerhalb derer jedes Zeichen w�rtlich (I<literal>) verstanden wird und besondere
Bedeutungen aufgehoben sind. Die einzigen beiden Ausnahmen sind C<\'> und C<\\>.
Ersteres ist notwendig um ein einfaches Anf�hrungszeichen innerhalb des Strings
zu erhalten, zweiteres f�r einen umgekehrten Schr�gstrich (I<Backslash>), der
normalerweise die besondere Bedeutung der Steuerzeichens (Metazeichens) aufhebt,
was auch I<escapen> genannt wird. Etwas in Anf�hrungszeichen zu setzten wird
auch I<quoting> (Zitieren) bezeichnet, weswegen ein C<q//> die generalisierte
Form von C<''> ist.

say '\''; # sagt: '
say q/\\/; # sagt: \
say q["\\"]; # dito, beliebige Klammern sin m�glich

Das sch�ne an Perl 6 ist allerdings nicht nur da� es sich hier bequem an Perl 5
angleicht, sondern da� das Bekannte (oft) zur allgemeing�ltigen Grundregeln wird.
C<''> hat �berall die gleiche Bedeutung, auch innerhalb eines regul�ren Ausdrucks.
Und C<q//> ist die Basis s�mtlicher I<quoting>-Operatoren die lediglich C<q//> mit
verschiedenen Optionen aufrufen. Aber um wirklich ehrlich zu sein: auch das ist
nur die halbe Wahrheit. Die echte Urvater aller I<quoting>-Operatoren ist das
C<Q>, welches gar nichts interpoliert und C<q//> ist ein I<Alias> auf C<Q :q //>.
Der Doppelpunkt vor dem "q" markiert einen benannten Parameter. Die ganze
Erkl�rung dazu steht in der vierten und f�nften Folge.

Komplexeres Quoting

Auch wenn die Einfachen oft ausreichend sind und minimal Rechenzeit sparen,
so sieht man �fter die doppelten Anf�hrungszeichen. Ihre Bedeutung blieb auch
im Wesentlichen unber�hrt. Innerhalb von C<""> werden Variablen evaluiert (durch
ihren Inhalt ersetzt) und I<Escapesequenzen> wie C<\n> (Zeilenende) oder C<\t>
(Tab) gegen entsprechende Sonder- oder Steuerzeichen ersetzt. Hinzu kam die an
Ruby erinnernde M�glichkeit, neben Subroutinen (hier mit "&" schreiben) nun auch
Bl�cke (I<Closures>) auszuf�hren.

say "Und die Zusatzzahl f�r $heute lautet: \t { int rand(47) }.";

Auch hier hat Larry konsequent vereinheitlicht. Bl�cke werden nun mal (wenn sie
kein Parameter sind) sofort ausgef�hrt. Und auch wer jetzt innerhalb einer Regex
etwas ausf�hren m�chte sollte sich dieses Mittels bedienen anstatt sich mit der
Option "e" oder C<(?{ ... })> einen Kompilererror einzufangen. Anstatt "ee" l��t
sich ein C<eval> in den Block einf�gen (Ausf�hrung des Ausf�hrungsergebnisses).

Damit ist eindeutig klar: C<""> oder alternativ auch C<qq//> ist ein I<Alias> auf
C<Q :s :a :h :f :c :b //>, oder? Verst�ndlicher wird es, wenn die "langen Formen"
der "Adverbien" verwendet werden (C<Q :scalar :array :hash :function :closure
:backslash //>). C<:scalar> besagt das Skalare evaluiert werde, C<:array> - Arrays
... und C<:backslash> bezieht sich auf die Steuerzeichen. Das impliziert auch
C<:q> aka C<:single>, da� hierf�r nicht extra angegeben werden mu�te. C<:qq>
lautet ausgeschrieben entsprechend C<:double>. Weitere I<quote>-"Adverbien" sind
C<:x> aka C<:exec>, was dem bekannten Perl 5-C<qx> entspricht, nur das C<qx> in
Perl 6 logischerweise nicht interpoliert, da es gleich C<q :x //> ist. C<:w> aka
C<:words> ist ebenfalls altbekannt, wird aber in Perl 6 idiomatisch "< >"
geschrieben (siehe dritte Folge).
C<:ww> aka C<:quotewords> entspricht dem bereits bekannten "<< >>".

my $ich = 'Prinz';
my @n = 1 .. 5;
say q:a/$ich sage: in \@n ist @n./
# sagt: $ich sage: in @n ist 1 2 3 4 5.

Heredocs

I<Heredocs> sind nun auch nichts besonderes (eigenst�ndiges) mehr, nur noch normale
I<quotings>, deren Ende mit einer definierten Zeichenkette markiert ist. Diese
kann nun beliebig einger�ckt sein. I<Heredocs> werden damit weit m�chtiger, ohne
erh�hten Lernaufwand.

my $letter = qq:to/END/
Dear $recipient:
Thanks!
Sincerely,
$me
END

Die Langform des C<:to>-Adverbs ist C<:heredoc>.

Die neuen Regex

Es gibt von diesen Adverbien noch einige mehr, diese haben jedoch nur eine lange
Form und nicht mehr direkt etwas mit Strings zu tun, da sie zu Code oder Regex
evaluiert werden. Denn Regul�re Ausdr�cke werden in Perl 6 nicht mehr als Strings
angesehen, sondern als eigenst�ndige Sprache innerhalb der Sprache (wie in Rebol).
Diese Sprache ist kontextfrei, was rekursive Ausdr�cke erlaubt, wie erst seit
Perl 5.10 m�glich. Und diese Sprache unterscheidet sich teilweise so stark von den
Regex in Perl 5, da� eine Zeit lang f�r sie ein neuer Begriff gepr�gt wurde (die
Perl "rules"). Somit wandelte sich der Ausdruck "Perl rules" von einer Angeberei
zur Erw�hnung einer normalen Tatsache. Mittlerweile setzte sich aber auch f�r die
neuen Regeln der Begriff Regex wieder durch.

Es war n�tig sie von Grund auf neu zu gestalten, da der Regex-Syntax mit der Zeit
zu un�bersichtlich und widerspr�chlich wurde. Dies war auch nur teilweise das
Verschulden von Larry oder Ilya, da viele Unsauberheiten der UNIX-Kultur
entstammen. Damals schien es noch eine gute Idee sich an die Standards zu halten
und Perl leicht erlernbar zu machen. Mittlerweile hat Perl selbst den Standard
gesetzt (PCRE) und es wird Zeit hier einiges gerade zu r�cken.

Eine Regex kann mit drei Schreibweisen in einem Skalar gespeichert werden:

my $rx = rx[abc];
my $rx = q:regex[abc];
my $rx = regex{abc};

Die dritte Variante ist aber nicht ganz das Selbe wie die ersten Beiden und kann
daher nur ausschlie�lich mit geschweiften Klammern geschrieben werden. Mehr dazu
wenn es um "Grammatiken" geht. Diese Skalare "wissen" ob sie ein Regexobjekt oder
einen einfachen String enthalten und deshalb wird die Schreibweise C<\Q$var\E>
�berfl�ssig. Auch ohne ihr w�rde eine Regex die aus Teilausdruck und einem String
wie folgende funktionieren.

$text ~~ m/ $rx $str /;

Oft werden Regex nicht gespeichert sondern direkt angewendet, was immer noch mit
C<m/.../> oder C<s/.../.../> oder den Sonderformen C<mm/.../> und C<ss/.../.../>
getan wird. Auch C<tr/.../.../> gibt es weiterhin.
Diese Operationen werden wie in Perl 5.10 mit dem I<Smartmatch> (~~) an einen
String gebunden. Das Resultat ist allerdings hier ein I<Matchobjekt>, da� im
boolschen Kontext zu C<Bool::True> oder C<Bool::False> evaluiert, damit C<if>,
C<when>, C<while> und C<until>, die diesen Kontext erzwingen, weiterhin arbeiten.
Das zuletzt im aktuellen Block erzeugte I<Matchobjekt> liefert auch die Variable
C<$/>, die alle Detailinformationen enth�lt. Andere, bisherige Sondervariablen
wurden abgeschafft. Allerdings sind C<$0> bis C<$9> I<Aliase> auf C<$/0> bis
C<$/9>. Als Trenner k�nnen weiterhin beinah beliebige Zeichen verwendet werden.
Aber Optionen werden nun (wie beim I<quoting>) als Adverbien vor die Trenner und
hinter den Namen der Operation gesetzt.

Regex Optionen

my $text = "Ich schreibe gerne udn schnell udn viel.";
$text ~~ s:g/udn/und/;

Ansonst sollte die Option ":g" bekannt sein. Ohne sie wird nur einmal ersetzt,
mit ihr, jedes Aufkommen. Auch die ":i"-Option, welche die Gross/Kleinschreibung
ignorieren l��t ist unver�ndert geblieben. �hnlich wie beim I<quoting> gibt es
auch hier f�r die ordentlichen Sch�nschreiber mit C<:global> und C<:ignorecase>
eine lange Version dieser Optionsnamen. Neu ist das Adverb C<:ii> aka C<:samecase>
welches ebenfalls die Gro�/Kleinschreibung des Suchausdrucks nicht genau nimmt,
ihn aber dann an die Schreibweise des Ersetzten anpasst.

my $text = "Ale V�gel sind schon da, ale ...";
$text ~~ s:g:ii/ale/alle/;
# $text eq "Alle V�gel sind schon da, alle ..."

In �hnlicher Weise gibt es nun auch C<:a> aka C<:ignoreaccent>, sowie C<:aa> aka
C<:sameaccent> das Buchstaben als gleich erkennen und ersetzen k�nnen, egal ob
sie einen Punkt, einen Strich, ein Dach oder nichts �ber sich haben. Dazu ignoriert
der Interpreter alle "I<mark characters>" zusammengesetzter I<Unicode>-Zeichen.

Es kamen etliche weitere Adverbien hinzu aber es wurden auch viele abgeschafft.
Neben den bereits erw�hnten C<:e> und C<:ee> betrifft das auch C<:m> und C<:s>.
C<^> und C<$> bedeuten nun immer Anfang und Ende des Strings.
C<^^> und C<$$> stehen f�r Anfang und Ende einer Zeile: Perl verwendet nat�rlich
das eigene C<\n> um Zeilen zu unterscheiden, was immer erfolgreich sein sollte,
egal auf welchem Betriebssystem das Programm gerade l�uft oder woher die Daten
kommen. Ein C<.> bedeutet jetzt wirklich "ein beliebiges Zeichen". Die alte
Bedeutung (ein beliebiges Zeichen au�er \n) nennt sich jetzt konsequenterweise C<\N>,
da gro�geschriebene Symbole f�r Zeichenklassen immer das Komplement�r zu ihrem
kleingeschriebenen Pendanten sind.

Auch die Option C<:x> ist weg, da Leerzeichen und Kommentare nun standardm��ig
eingef�gt werden k�nnen, soweit keine besondere Regel etwas anderes vorschreibt.
Der Syntax von Kommentaren ist innerhalb der Regex der Selbe wie au�erhalb. Eine
Raute kommentiert bis zum Ende der Zeile, folgt der Raute beliebige Klammersymbole,
gilt bis zum Schlie�en dieser Klammern der Inhalt der Regex als Kommentar.

Eine der Regeln die Leerzeichen besondere Bedeutung geben k�nnen ist C<:s> aka
C<:sigspace>. Wird sie gew�hlt, z�hlt jedes Leerzeichen als "<.ws>", was grob
mit C<\s+> (mehrere Leerzeichen verschiedenster Art) �bersetzt werden kann.
Diese I<sigspace> findet Larry so bedeutend, da� C<m:s/.../> gleichbedeutend mit
C<mm//> ist. Ein C<ss/.../.../> entspricht allerdings einem C<s:ss/.../.../>.
C<:ss> aka C<:samespace> unterscheidet sich von C<:sigspace> nur insoweit, da�
auch zwischen dem zweiten und dritten Trenner jedes Leerzeichen als "<.ws>" gilt.

my $lied = "Der Mond\nist\taufgegangen ...";
ss/Mond ist aufgegangen/Plumssack geht im/;
# "Der Plumssack\ngeht\tim".

Sehr praktisch finde ich auch die Optionen C<:c> aka C<:continue> und C<:p> aka
C<:pos>. Ersteres sucht ab einer Position, zweiteres nur an einer Position. Wird
keine Zahl f�r die Position angegeben, so wird diese C<$/.> entnommen.

my $text = "Vom Eise befreit sind Strom und B�che."
if $text ~~ m:c(3)/Eis/ {
# wird ausgef�hrt
...
if $text ~~ m:p(3)/Eis/ {
# wird nicht ausgef�hrt
...

Was genau gez�hlt werden soll, kann mit den Adverbien C<:bytes>, C<:codes>
(I<Unicode codepoints>), C<:graphs> und C<:chars> angegeben werden.

Soll eine Ersetzung nur dreimal ausgef�hrt werden so hilft C<:3x> aka C<:x(3)>
und falls nur der f�nfte Fund einer Suche interessiert, so steht dazu C<:5th>
aka C<:nth(5)> bereit. C<:1st>, C<:2nd> und C<:3rd> sind Sonderformen die eine
nat�rliche Ausdrucksweise erlauben sollen und auch I<Junctions> wie C<nth(3|5|7)>
sind m�glich. Die Bedeutung runder Klammern hat sich nicht ver�ndert. Sie
umschlie�en nach wie vor Teilausdr�cke, deren Fund bitte gespeichert werden soll.
Teilausdr�cke deren Fund nicht interessiert werden jetzt in eckige Klammern
gesetzt anstatt in C<(?: ... )>.

s:3rd/(\d+)/@data[$0]/;
# ist das selbe wie:
m/(\d+)/ && m:c/(\d+)/ && s:c/(\d+)/@data[$0]/;

Die Regeln f�r die Nummerierung von C<$0> bis C<$9> haben sich auch ge�ndert, da
bisher kleine �nderungen in der Regex manchmal zu viele Nachbesserungen in dem
Code forderte, der diese Variablen auswertet, da eine ung�nstig gesetzte Klammer
die Position aller anderen ver�ndert. Sind Klammern hintereinander wie in C<()()>,
werden sie immer noch genauso gez�hlt. In einem Fall wie C<(... (...) )> w�re der
Fund der inneren Klammer in C<$0[0]>.

Was mich ebenfalls begeisterte sind die die neuen Optionen C<:ov> aka C<:overlap>
und C<:ex> aka C<:exhaustive> die am besten an einem Beispiel verstanden werden.

$str = "abracadabra";

if $str ~~ m:overlap/ a (.) a / {
@substrings = @@();
# bracadabr cadabr dabr br
}
if $str ~~ m:exhaustive/ a (.?) a / {
say "@()";
# br brac bracad bracadabr c cad cadabr d dabr br
}

Da C<$0> bis C<$9> oft nicht reichen, gibt es C<@()>, der alle Funde enth�lt.
Um das Suchverhalten zu steuern, kann auch die neue Option C<:ratchet> hilfreich
sein, die jegliches I<Backtracking> verhindert. Das bedeutet, da� Perl den zu
durchsuchenden String nur ein einziges mal von links nach rechts �berpr�ft und
dabei niemals r�ckw�rts geht, selbst wenn in der Regex Alternativen formuliert
sind die erfolgreich sein k�nnten wenn die Suche noch einmal begonnen w�rde.
Das I<Backtracking> kann aber auch f�r einzelne Teilausdr�cke abgestellt werden,
indem ihm ein C<:> nachgestellt wird (ehemals "(?> ...)").

Quanto costa?

Die sogenannten I<quantifier> haben sich kaum ver�ndert. C<?> steht immer noch
daf�r den Teilausdruck nicht oder nur einmal zu finden, C<+> f�r einmal oder
beliebig oft und C<> f�r keinmal oder beliebig oft. Auch die nicht gierigen
I<quantifier> (C<??, ?, +?>) haben sich in Syntax und Semantik (Bedeutung) nicht
ver�ndert. Nur exakte I<quantifier> werden anders geschrieben, da geschweifte
klammern wie beschrieben immer Bl�cke darstellen. Die neue Schreibweise, der
aufmerksame Leser ahnt es bereits, entstammt dem allgemeinem Perlsyntax. Wenn ein
Multiplikationszeichen Wiederholungen bezeichnet, dann kann eine vierfache
Wiederholung ja nur C<**4> lauten. Und darf sich ein Teilausdruck nur ein bis
dreimal wiederholen so wird dies C<()**1..3> geschrieben.

Nichts ist illegal

Mit Perl 6 gibt sich Larry auch gro�e M�he Zweideutigkeiten zu vermeiden. Ein
simples:

$text ~~ m/ /;

wirft jetzt einen wundersch�nen Error in die Kommandozeile. Um die letztbenutze
Regex wiederzuverwenden schreibe man:

$text ~~ m/ <prior> /;

Oder falls tats�chlich nichts gesucht wird, gibt es die Schreibweisen C<''> und
"<?>". Wird eine Alternative beim Programmieren vergessen wird dies nun sofort
sichtbar. Ja auch das C<|> hat sich in seiner Bedeutung nicht ver�ndert.

$text ~~ m/ |_+ /;

Diese Regex sucht W�rter die aus Buchstaben und Unterstrichen bestehen.
Was vorher Dach war (Komplement�rmenge an Zeichen) ist nun Minus. Oder anschaulich:
Keine hexadezimale Zahlen, die man fr�her mit der Gruppe C<^0-9a-f> erfasst hat,
werden jetzt mit "<-0-9a-f>" gesucht. In diesem Falle w�rde es "<-hexdigit>"
allerdings auch tun.

Wendeh�lse

Vorschau (I<lookahead>) und R�ckschau (I<lookbehind>) haben ihre Schreibweise
ge�ndert und sind nun lesbarer. Angelehnt an logische Operatoren wie den Tern�ren
bezeichnet ein C<?> immer eine positive und C<!> eine negative Option. Folglich
wurde C<(?= ...)> zu <?before ...> und C<(?! ...)> zu <!before ...>. Entsprechend
�nderte sich C<(?<= ...)> zu <?after ...> und C<(?<! ...)> zu <!after ...>. Mit
solchen Teilausdr�cken verlangt man welche Zeichen vor oder hinter dem gesuchten
Teilstring gew�nscht oder unerw�nscht sind. Eine detaillierte Erkl�rung dazu hat
das perlretut in den I<perldocs>.

Wer sp�testens jetzt bei all den Neuerungen und �nderungen die Lust verliert,
kann mit C<:P5> aka C<:Perl5> die alten Regeln wieder einsetzen. Jedoch m��en
Optionen auf jeden Fall vor die Regex oder in sie hinein in eine C<(?m ...)> Gruppe.

Die gro�e Perpektive

Auch wenn mit dem neuen Syntax viele Details klarer werden, k�nnen Regex immer
noch schnell unleserlich werden, wenn komplexe Zusammenh�nge eingelesen und
aufgespalten werden sollen. (Wir bauen mal schnell einen HTML-Parser.) Hierf�r
br�uchte es Mittel wie lex und yacc, die ein Stufenweises aufspalten erlauben.
Die dazu verwendeten Regeln w�ren verst�ndlicher und einfacher wiederverwendbar.
Genau diese �berlegungen stehen hinter den Perl 6-Grammatiken. Eine C<grammar>
ist in Wirklichkeit eine Klasse, deren Methoden Regex sind. Deshalb behandelt
dieses Tutorial auch die Regex nach der OOP, obwohl Strings ein elementares
Thema f�r Perlprogrammierer sind. F�r C<grammar> wurden 3 spezielle Typen von
Routinen geschaffen. Dies w�re zum einen C<regex>. Damit wird klar warum die
Schreibweise C<regex name {}> geschweifte Klammern verlangt. Eine C<sub> wird
ebenfalls nur mit geschweiften Klammern geschrieben. Um das Parsen einfacherer
Regeln effektiver und das Kombinieren von Teilregeln optisch zu vereinfachen gibt
es noch den Routinentyp C<rule>. Der entspricht C<regex :ratchet :sigspace {...}>.
Der dritte Typ (C<token>) wurde geschaffen um Grundbausteine zu definieren und
entspricht C<regex :ratchet { ... }>. Ein Grammatik um eine Flie�kommazahl zu
zerlegen s�he ungef�hr so aus:

grammar Float {
rule digits { \d+ }
rule sign { \+ | - }
rule exp :i { e <sign>? <digits> }
rule man { \. <digits> | <digits> [ \. <digits>? ]? }
rule top { <sign>? <man> <exp>? }
}

Einzelne C<rules> definieren Teilausdr�cke die sp�tere C<rules> verwenden, indem
sie den Namen der C<rule> in spitze Klammern setzen. Spitze Klammern und Punkt
markieren Teilausdr�cke deren Fund nicht gespeichert wird. (wie das erw�hnte <.ws>)
Diese C<rules> sind tats�chlich Routinen denn ich kann sie wie welche aufrufen.

my $result = Float.top("-6.02e+23");

In C<$/{'man'}> oder C<$result{'man'}> steht nun z.B. "6.02", in C<$/{'exp'}{'sign'}>
ein Pluszeichen, da dies das Vorzeichen des Exponenten ist. Aus Folge vier wissen
wir das Hashschl�ssel auch einfacher geschrieben werden k�nnen, z.B. "$/<sign>".
Nun kann man erkennen wieviel Sinn es macht, benannte Teilausdr�cke in spitze
Klammern zu setzen, da die Hashschl�ssel unter denen ihr Fund gespeichert ist,
gleich aussehen. �hnliches war innerhalb einer Regex ab Perl 5.10 nur mit
"(?<name> ...)" erreichbar. Grammatiken sind allerdings wie (andere Klassen auch)
ableitbar und k�nnen so einfach auf bereits bekannte Art kombiniert und erweitert
werden. Dies ist nicht nur praktisch sondern erlaubt erst viele besondere
F�higkeiten von Perl 6, da� damit immer mehr zu einer Meta-Programmiersprache
mutiert. Metaprogrammierung wird jedoch Thema der n�chsten und letzten Folge sein.


Previous Chapter | Overview | Next Chapter


 

Upload Files

Click "Browse" to find the file you want to upload. When you click "Upload file" your file will be uploaded and added to the list of attachments for this page.

Maximum file size: 50MB

 
 
 
File Name Author Date Uploaded Size

Save Page As

Enter a meaningful and distinctive title for your page.

Page Title:

Tip: You'll be able to find this page later by using the title you choose.

Page Already Exists

There is already a page named XXX. Would you like to:

Save with a different name:

Save the page with the name "XXX"

Append your text to the bottom of the existing page named: "XXX"

Upload Files

Click "Browse" to find the file you want to upload. When you click "Add file" this file will be added to the list of attachments for this page, and uploaded when you save the page.

 
 
 
Add Tags

Enter a tag and click "Add tag". The tag will be saved when you save the page.

Tag: 

Suggestions: