Mac Perl Primer

Datenkonvertierung und Droplets

Wir stellen uns folgendes Szenario vor: wir haben mit einem Standardbüroprogramm wie z.B. Clarisworks unsere CD-Sammlung archiviert und möchten sie nun im Internet zum Tauschen zur Verfügung stellen. Wir können die Daten z.B. als ASCII-Datei ausgeben. Eine solche Datei sieht typischerweise dann folgendermaßen aus:

1 Prince Sign of the Times 1987
2 Laurie Ariale Trio The Eyes have it 1994
3 rad gotta be 1993

Zwischen den einzelnen Daten sind jeweils Tabulatorzeichen. Wenn wir diesen Katalog auf einer HTML Seite darstellen wollen, so sieht das am schönsten als Tabelle aus.
Der HTML-Code dazu lautet folgendermaßen:

<TABLE>
<TR><TD>1</TD><TD>Prince</TD><TD>Sign of the Times</TD><TD>1987</TD></TR>
...
</TABLE>

Wir wollen jetzt die Daten aus den einen Format in das andere konvertieren. Eine typische Anwendung, in der Perl seine Stärken in der Textbearbeitung ausspielen kann. Wir werden ein solches Konvertierungsprogramm in kleinen Schritten entwickeln. Wir fangen mit folgenden Programm an:

print "<TABLE>\n";                        #-- write Table Header

while(<>) {                               #-- Loop over all Lines
    @data = split /\t/;                   #-- extract data entries
    print "<TR>";                         #-- write Table row start
    foreach $field (@data) {              #-- Loop over data entries
        print "<TD>$field</TD>";          #-- write table cell
    }                                     #-- end loop data entires
    print "</TR>\n";                      #-- write table row end
}                                         #-- End Loop Lines

print "</TABLE>\n";                       #-- write Table Footer

Diese paar Zeilen genügen für das Gerüst zur Konvertierung. Aber zunächst erkläre ich die wichtigsten Zeilen:

while(<>) {
...
}

Das <> Konstrukt (genauer: Operator) liest eine Zeile von der sogenannten Standardeingabe ein und speichert sie in einer Defaultvariablen zwischen. Die Defaultvariable heißt übrigens $_, und so sind die beiden eckigen Klammern in Wirklichkeit eine Abkürzung für $_ = <STDIN>
Achtung: Damit diese Abkürzung funktioniert, darf zwischen den eckigen Klammern kein Leerzeichen stehen.
Wie lang die Zeile ist, ist übrigens Perl ziemlich egal. Das while Konstrukt sorgt dafür, das immer wieder eine neue Eingabezeile gelesen wird, und dann die Anweisungen innerhalb der geschweiften Klammer ausgeführt werden. Es bricht ab, wenn keine Eingabezeilen mehr da sind, genau wie wir uns das auch vorstellen.

Für jede Eingabezeile werden im wesentlichen zwei Anweisungen ausgeführt: Erstens die split Anweisung. Sie trennt die Eingabezeilen an den angegebenen Zeichen (\t für Tabulator) und liefert eine Liste mit den Datenfeldern zurück. Diese Liste wird in der Listenvariablen @data gespeichert. Das @ kennzeichnet in Perl, das es sich um eine Listenvariable handelt.

Darauf hin kommen die Ausgabe Anweisungen, die dafür sorgen, das das neue Format ausgegeben wird. Die foreach Anweisung bewirkt daß das ihr inneres für jedes Element der Liste @data einmal ausgeführt wird.

Wenn wir das Programm mit skript->run laufen lassen, passiert erstmal garnichts. Im Perl Fenster erscheint der Text <table> und ein Cursor blinkt vor sich hin. Was ist falsch? Garnichts! Das Programm wartet auf seine Eingabe und sagt UNIX-typisch nichts.
Wir geben im Perl Fenster folgendes ein:

1[TAB]Prince[TAB]Sign of the Times[TAB]1987[RETURN]

wobei mit [TAB] und [Return] ich die jeweilige Taste meine.

Perl antwortet mit folgenden Zeilen:

<TR><TD>1</TD><TD>Prince</TD><TD>Sign of the Times</TD><TD>1987
</TD></TR>

Immerhin liefert Perl etwas zurück, was schon ganz gut aussieht. Aber das Verfahren, die Zeilen einzeln einzugeben, ist natürlich nicht das, was wir uns erhoffen. Wir werden aber später sehen, wie wir eine ganze Datei in einem Rutsch verarbeiten. Im Moment bleiben wir bei der zeilenweisen Eingabe, weil wir so sehr schön alles testen können. Wir geben eine zweite Zeile ein:

2[TAB]Beatles[TAB]White Album[TAB]1966

Perl antwortet mit

<TR><TD>2</TD><TD>Beatles</TD><TD>White Album</TD><TD>1966
</TD></TR>

Uns fällt noch folgendes auf: Perl fängt unmotiviert nach der Jahreszahl mit einer neue Zeile an. Obwohl das für HTML nicht so wichtig ist, wollen wir doch wissen, ob es nicht auch besser geht. Unser Programm braucht also noch eine Überarbeitung. Wir versuchen das MacPerl Fenster zu schließen, aber es funktioniert nicht! Der Mac piepst nur, aber schließt das Fenster nicht! '(Zumindestens noch in der Version 5r13) Der Grund liegt darin, das unser selbstgeschriebenes Programm noch läuft. Wir müssen es mit der Tastenkombination [CRTL][D] abbrechen. Danach gibt unser Programm auch noch das letzte </table> aus. Das Symbol in der unteren Ecke des MacPerl Fensters verändert sich vom Stift (Hier darf man schreiben) in ein Vorhängeschloß (Dieses Fenster kann man nicht verändern).

Warum brechen wir das Programm mit [CRTL][D] und nicht Apfel-Q ab: Das hat mehrere Gründe: Apfel-Q bricht MacPerl insgesamt ab, und [CRTL][D] bricht das Programm eigentlich nicht ab, sondern gibt ein "Ende der Eingabe" Zeichen ein. Das Programm (vielmehr das while Konstrukt) merkt dann, es es nichts mehr zu tun hat, gibt noch da letzte </table> aus und beendet sich dann selbst.

Jetzt können wir auch Verbesserungen vornehmen. Der unerwünschte Zeilenumbruch rührt daher, das beim lesen der Eingabezeile das Zeilenumbruchszeichen mit eingelesen wurde, und am Schluss schließlich auch ausgegeben wurde. Um das letzte Zeichen einer Zeile zu entfernen, gibt es in Perl eine extra Funktion namens chop.

print "<TABLE>\n";                        #-- write Table Header

while(<>) {                               #-- Loop over all Lines
    chop;                                 #-- remove the newline char
    @data = split /\t/;                   #-- extract data entries
    print "<TR>";                         #-- write Table row start
    foreach $field (@data) {              #-- Loop over data entries
        print "<TD>$field</TD>";          #-- write table cell
    }                                     #-- end loop data entires
    print "</TR>\n";                      #-- write table row end
}                                         #-- End Loop Lines

print "</TABLE>\n";                       #-- write Table Footer

Wir probieren das Programm wieder aus : Der Zeilenumbruch ist verschwunden. Jetzt bleibt aber noch das Problem, das wir natürlich nicht alles per Hand eingeben wollen. Hier hat MacPerl aber eine schöne Lösung:

Icon Droplets

Wir sichern unser Programm als sogenanntes Droplet ( File->Save As, Filetype droplet). Ich empfehle, allen diesen Droplets ein Kürzel anzuhängen, als z.B. ".drop". Was ist nun ein Droplet ? Das sehen wir am besten in Aktion: Dazu wechseln wir in den Finder und suchen unser Droplet. Dann nehmen wir eine Datei, die wir konvertieren möchten (Wer keine passende Datenbankdatei hat, kann sich hier eine Beispieldatei runterladen) Wir ziehen diese Datei auf unser Droplet. MacPerl öffnet sich und zeigt nach kurzer Zeit in einem Fenster die konvertierten Daten an. Jetzt können wir entweder mit Copy&paste die Daten übernehmen oder das Fenster mit File->Save as sichern.

Einschub:
Alpha: Ein alternativer Texteditor für MacPerl

<- vorherige Lektion

>- nächste Lektion


home - contact - q-zone - dev-zone