Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Einführung
2 Mathematische und technische Grundlagen
3 Hardware
4 Netzwerkgrundlagen
5 Betriebssystemgrundlagen
6 Windows
7 Linux
8 Mac OS X
9 Grundlagen der Programmierung
10 Konzepte der Programmierung
11 Software-Engineering
12 Datenbanken
13 Server für Webanwendungen
14 Weitere Internet-Serverdienste
15 XML
16 Weitere Datei- und Datenformate
17 Webseitenerstellung mit (X)HTML und CSS
18 Webserveranwendungen
19 JavaScript und Ajax
20 Computer- und Netzwerksicherheit
A Glossar
B Zweisprachige Wortliste
C Kommentiertes Literatur- und Linkverzeichnis
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
IT-Handbuch für Fachinformatiker von Sascha Kersken
Der Ausbildungsbegleiter
Buch: IT-Handbuch für Fachinformatiker

IT-Handbuch für Fachinformatiker
Rheinwerk Computing
1216 S., 6., aktualisierte und erweiterte Auflage, geb.
34,90 Euro, ISBN 978-3-8362-2234-1
Pfeil 10 Konzepte der Programmierung
Pfeil 10.1 Algorithmen und Datenstrukturen
Pfeil 10.1.1 Ein einfaches Praxisbeispiel
Pfeil 10.1.2 Sortier-Algorithmen
Pfeil 10.1.3 Such-Algorithmen
Pfeil 10.1.4 Ausgewählte Datenstrukturen
Pfeil 10.2 Reguläre Ausdrücke
Pfeil 10.2.1 Muster für reguläre Ausdrücke
Pfeil 10.2.2 Programmierung mit regulären Ausdrücken
Pfeil 10.3 Systemnahe Programmierung
Pfeil 10.3.1 Prozesse und Pipes
Pfeil 10.3.2 Threads
Pfeil 10.4 Einführung in die Netzwerkprogrammierung
Pfeil 10.4.1 Die Berkeley Socket API
Pfeil 10.4.2 Ein praktisches Beispiel
Pfeil 10.4.3 Ein Ruby-Webserver
Pfeil 10.5 Verteilte Anwendungen mit Java Enterprise Edition
Pfeil 10.5.1 Enterprise Java Beans (EJB)
Pfeil 10.5.2 Java Servlets
Pfeil 10.5.3 Webservices
Pfeil 10.6 GUI- und Grafikprogrammierung
Pfeil 10.6.1 Zeichnungen und Grafiken erstellen
Pfeil 10.6.2 Animation
Pfeil 10.6.3 Programmierung fensterbasierter Anwendungen
Pfeil 10.6.4 Java-Applets
Pfeil 10.7 Zusammenfassung

Rheinwerk Computing - Zum Seitenanfang

10.2 Reguläre AusdrückeZur nächsten Überschrift

Bereits in Kapitel 7, »Linux«, wurden Beispiele für die Mustererkennung im Konsolen-Dienstprogramm grep gezeigt. In der Softwareentwicklung spielt die Arbeit mit Textmustern eine sehr wichtige Rolle. Denken Sie nur einmal an die Verarbeitung zahlreicher Personendaten oder Verwaltungsinformationen bei Behörden oder großen Unternehmen. Es wäre mehr als mühselig, solche Datenbestände mithilfe konventioneller Einzeltextvergleiche in den Griff bekommen zu wollen.

Deshalb wurde ein besonderes Verfahren entwickelt: die Arbeit mit regulären Ausdrücken. Der Begriff regulärer Ausdruck ist eigentlich ein wenig unglücklich gewählt. Es handelt sich um die Übersetzung des englischen Begriffs regular expression (abgekürzt RegExp), den man besser als »regelgerechten Ausdruck« wiedergeben würde.

Die beste Unterstützung für reguläre Ausdrücke bietet traditionellerweise die Programmiersprache Perl, denn sie wurde vor allem zu diesem Zweck entworfen. Die Syntax für reguläre Ausdrücke, die in Perl eingesetzt wird, geht weit über die Möglichkeiten von grep hinaus. Sie stammen zum großen Teil von den Unix-Textverarbeitungssprachen sed und awk. Reguläre Ausdrücke werden auch von zahlreichen anderen Programmiersprachen unterstützt, etwa von Ruby, Java und dem Microsoft .NET Framework.

Da reguläre Ausdrücke das Programmieren erheblich erleichtern können, wird ihnen an dieser Stelle ein ganzer Abschnitt gewidmet; er konzentriert sich auf Perl und Ruby. Zusätzlich erfahren Sie in Kapitel 18, »Webserveranwendungen«, und in Kapitel 19, »JavaScript und Ajax«, kurz, wie Sie in PHP beziehungsweise JavaScript mit regulären Ausdrücken umgehen.

In Perl werden vor allem zwei wichtige Operatoren zusammen mit regulären Ausdrücken verwendet:

  • String =~ m/RegExp/ sucht in einem String nach dem Vorkommen von RegExp. In den meisten Fällen kann das m vor dem / einfach weggelassen werden.
  • String =~ s/RegExp/String/ ersetzt ein gefundenes Vorkommen von RegExp durch den angegebenen String.

In Ruby funktionieren diese RegExp-Anwendungsfälle wie folgt:

  • String =~ Regexp vergleicht den angegebenen String mit dem regulären Ausdruck.
  • String.sub(RegExp, Ersatztext) ersetzt das erste Vorkommen des regulären Ausdrucks.
  • String.gsub(RegExp, Ersatztext) führt die Ersetzung an allen Fundstellen durch.
  • Die Klasse Regexp, auf die hier nicht näher eingegangen werden kann, bietet einen explizit objektorientierten und somit noch »Ruby-gemäßeren« Zugang zu regulären Ausdrücken.

Es ist nicht so schwierig, das Funktionieren dieser Operatoren oder Funktionen selbst zu verstehen. Wichtiger ist es, zu lernen und sich zu merken, welche Formulierungen in regulären Ausdrücken zulässig sind.


Rheinwerk Computing - Zum Seitenanfang

10.2.1 Muster für reguläre AusdrückeZur nächsten ÜberschriftZur vorigen Überschrift

Zuerst müssen Sie verstehen, dass ein regulärer Ausdruck standardmäßig keinen kompletten String beschreibt, sondern bereits als Treffer gilt, wenn er auf einen beliebigen Teilstring zutrifft. Wichtig ist dies bei sicherheitsrelevanten Anwendungen, etwa bei der Überprüfung von Benutzereingaben: Die Tatsache, dass die Eingabe einem bestimmten Muster entspricht, heißt noch nicht automatisch, dass sie frei von schädlichen Inhalten sein muss. Deshalb gibt es spezielle Elemente, die den Anfang und das Ende eines Strings bezeichnen.

Dazu ein Beispiel vorweg: a bedeutet, dass der Buchstabe a an einer beliebigen Stelle im untersuchten Text stehen darf. ^a steht dagegen für ein a am String-Anfang.

Grundsätzlich existieren unter anderem die folgenden Komponenten für einzelne Zeichen, aus denen Sie in Perl und Ruby reguläre Ausdrücke zusammensetzen können:

  • abc steht einfach für die genannten Zeichen selbst. ee passt auf »Tee« und »See«, aber nicht auf »Tea«.
  • [abc] steht für ein beliebiges Zeichen aus der Liste. [MH]aus passt also auf »Haus« und »Maus«, aber nicht auf »raus«.
  • [a-z] steht für die gesamte angegebene Zeichenfolge im Zeichensatz. Beispielsweise bedeutet [a-z], dass alle kleinen Buchstaben gemeint sind, [0-9] steht dagegen für alle Ziffern und so weiter. Natürlich müssen Sie nicht immer eine ganze Zeichenkategorie angeben: [A-K] repräsentiert zum Beispiel alle großen Buchstaben von A bis K. Außerdem können Sie innerhalb desselben Paares eckiger Klammern sowohl einen Bereich als auch einzelne Zeichen eingeben. [a-dp] trifft etwa auf alle Zeichen von a bis d sowie auf das p zu. Auch mehrere Bereiche sind möglich: Beispielsweise stellt [0-9a-fA-F] sämtliche Hexadezimalziffern dar.
  • [^abc] steht für jedes beliebiges Zeichen außer denjenigen in der Liste. So trifft [^M]aus auf »Haus« und »raus«, aber nicht auf »Maus« zu. Übrigens passt dieser Ausdruck auch nicht auf »aus«, weil auf jeden Fall ein Zeichen davor erwartet wird – es darf nur kein M sein.
  • . (ein Punkt) steht für genau ein beliebiges Zeichen.

Diese und alle komplexeren RegExp-Konstrukte lassen sich durch sogenannte Quantifizierer (Quantifiers) modifizieren; diese stehen hinter einem bestimmten Element und geben jeweils an, wie oft es vorkommen darf. Die drei einfachen Quantifizierer sind:

  • ? bedeutet, dass das links davon stehende Zeichen beziehungsweise die Liste optional ist, also vorkommen darf oder auch nicht. Hau?se kann also für »Hase« oder für »Hause« stehen, aber nicht für »Hanse«.
  • * bedeutet, dass das links davon stehende Zeichen beziehungsweise die Liste beliebig oft vorkommen darf, also gar nicht, einmal oder öfter. 12*3 könnte also etwa 13, 123 oder 12223 heißen. .* steht übrigens für beliebig viele beliebige Zeichen.
  • + bedeutet, dass das links davon stehende Zeichen beziehungsweise die Liste mindestens einmal vorkommen muss, aber auch öfter vorkommen darf. 0,3+ kann also etwa für 0,3, 0,333 oder 0,333333333 stehen.

Die Quantifizierer * und + sind »gierig« (greedy): Wenn sie die Wahl haben, passen sie auf die maximal mögliche Anzahl von Zeichen. Falls Sie etwa mithilfe von ".*" nach Text in Anführungszeichen suchen, passt dieser Ausdruck auf sämtlichen Text zwischen dem ersten und dem allerletzten Anführungszeichen im aktuellen Bereich! Deshalb existiert alternativ eine »nicht gierige« (non-greedy) Variante: Schreiben Sie *? oder +?, wenn Sie nur jeweils den kleinstmöglichen Treffer erhalten möchten. Für einen einzelnen Textblock in Anführungszeichen müsste der Ausdruck also ".*?" lauten.

  • {n} bedeutet, dass das links davon stehende Zeichen beziehungsweise die Liste genau n-mal vorkommen muss. Beispielsweise ist [0-9]{5} das Muster für eine deutsche Postleitzahl: fünf Ziffern zwischen 0 und 9.
  • {m,n} bedeutet, dass das links davon stehende Zeichen beziehungsweise die Liste mindestens m-mal und höchstens n-mal vorkommen darf. Ein sinnvolles Muster für Telefonnummern ohne Vorwahl ist zum Beispiel [0-9]{4,8}.

Damit Sie die bisherigen Informationen leichter verarbeiten können, sehen Sie hier zunächst ein kurzes Beispiel. Das folgende Perl-Programm überprüft bei einer eingegebenen Zeile, ob sie das Wort »Perl« enthält:

#!/usr/bin/perl -w
print "Geben Sie etwas ein: ";
$zahl = <>;
if ($zahl =~ /Perl/) {
print "Danke für Perl!\n";
} else {
print "Da war kein Perl!\n";
warnung}

Falls Sie in regulären Ausdrücken bestimmte Zeichen als solche verwenden möchten, müssen Sie ihnen einen Backslash (\) voranstellen, weil sie eine spezielle Bedeutung haben. Es handelt sich um folgende Zeichen: – + ? * ( ) [ ] { } / \ | , . ^ $. Darüber hinaus müssen Sie in Perl % und @ schützen, weil sie einen Hash beziehungsweise ein Array einleiten.

Neben den bisher besprochenen Formen für einzelne Zeichen existieren etliche interessante Kurzfassungen und spezielle Formulierungen, von denen hier nur die wichtigsten wiedergegeben werden:

  • \s steht für beliebigen Whitespace, das heißt für Leerzeichen, Tabulatoren oder Zeilenumbrüche (falls überhaupt mehr als eine Zeile auf einmal verarbeitet wird).
  • \w repräsentiert sämtliche Arten von Zeichen, die in Wörtern vorkommen können. Genauer gesagt sind alle Zeichen zulässig, die in Perl-Bezeichnern vorkommen können: Buchstaben, Ziffern und _ (Unterstrich).
  • \W ist das Gegenteil von \w: Es trifft auf sämtliche anderen Zeichen zu.
  • \d steht für sämtliche Ziffern, ist also eine Abkürzung für [0-9].
  • \D stellt dagegen sämtliche Zeichen dar, die keine Ziffern sind; dies ist eine Abkürzung für [^0-9].
  • \b trifft auf Wortgrenzen zu. Diese Komponente ist also überall dort zu finden, wo ein Wort beginnt oder aufhört. Zum Beispiel findet \ber die Wörter »er« oder »erklären«, aber nicht »lernen«.
  • \B betrifft dagegen sämtliche Stellen innerhalb von Wörtern. Ein Muster, das Sie mit \B kombinieren, wird also nur dann gefunden, wenn es nicht am Anfang oder am Ende eines Wortes steht. \Ber findet also etwa »lernen«, aber nicht »erklären«.
  • () dient dazu, einen Teilausdruck zu einer Gruppe zusammenzufassen. Dies hat zum einen den Zweck, ganze Gruppen mit Zählern wie +, ? und * zu versehen oder mithilfe von | Optionen anzugeben; zum anderen merkt sich die Perl-RegExp-Engine geklammerte Ausdrücke in den speziellen Variablen $1 bis $9, um sie beim Ersetzen in den Ersatztext aufzunehmen.
  • ^ außerhalb eckiger Klammern steht für den Zeilenanfang. ^H trifft also beispielsweise auf den Text »Hallo Welt!« zu, aber nicht auf den Satz »Sag’ Hallo zur Welt!«.
  • $ steht entsprechend für das Zeilenende. Beispielsweise trifft \d+0$ nur auf Zahlen zu, die mit einer 0 enden.

    Der folgende Ausdruck trifft nur zu, wenn die gesamte Zeile aus einer Ganzzahl besteht:

    /^\-?\d+$/

    ^ markiert den Zeilenanfang, \-? steht für ein optionales Minuszeichen, dahinter bezeichnet \d+ eine oder mehrere Ziffern, und das Zeilenende wird durch $ gekennzeichnet.

Mithilfe geklammerter Ausdrücke können Sie eine noch größere Flexibilität erreichen. Beispielsweise passt der nächste Ausdruck auf »Hund«, »Katze« oder »Maus«:

/(Hund|Katze|Maus)/

Ein weiteres interessantes Hilfsmittel bei der Arbeit mit regulären Ausdrücken sind diverse Modifikatoren, die hinter den schließenden Slash geschrieben werden:

  • /i verzichtet auf die Unterscheidung zwischen Groß- und Kleinschreibung. /[a-z]+/i findet also beispielsweise beliebige Kombinationen von Buchstaben in beiden Schreibweisen.
  • /e erlaubt die Verwendung eines auszuwertenden Ausdrucks als Ersatztext. Normalerweise ist nur ein einfacher String gestattet. Trotz aller Perl-Kompatibilität der RegExp-Implementierungen anderer Sprachen und Programme funktioniert diese eine Option ausschließlich in Perl. In Ruby können Sie der Ersetzungsmethode gsub stattdessen einen Codeblock übergeben.
  • /g (nur Perl) findet mehr als einen Treffer, kann also etwa in einer Schleife abgearbeitet werden oder bei Ersetzungen dafür sorgen, dass nicht nur das erste Vorkommen ersetzt wird, sondern alle. Ruby verwendet für das Ersetzen aller Fundstellen stattdessen die spezielle Methode gsub.

Rheinwerk Computing - Zum Seitenanfang

10.2.2 Programmierung mit regulären AusdrückenZur vorigen Überschrift

Nachdem Sie nun die einzelnen Bestandteile regulärer Ausdrücke kennengelernt haben, müssen Sie als Nächstes die verschiedenen Perl- und Ruby-Funktionen erlernen, in denen reguläre Ausdrücke verwendet werden können.

Die einfachste dieser Funktionen ist der Matching-Operator m//, der überprüft, ob ein angegebener regulärer Ausdruck in einem String vorkommt. Er wird in der Regel zusammen mit einem der beiden Operatoren =~ oder !~ verwendet. Der Wert des Operators =~ ist wahr, wenn der reguläre Ausdruck auf der rechten Seite zu dem Ausdruck auf der linken Seite passt. Das Gegenteil ist bei !~ der Fall: Dieser Operator liefert den Wert »wahr«, wenn der reguläre Ausdruck auf der rechten Seite nicht zum untersuchten Ausdruck links passt.

Beispielsweise können Sie folgendermaßen überprüfen, ob in der Variablen $test Ziffern vorkommen:

print "Ziffern gefunden!" if $test =~ /\d/;

Mithilfe der folgenden Anweisung lässt sich dagegen testen, ob $test keine Buchstaben enthält:

print "Buchstabenfrei!" if $test !~ /[a-z]/i;

Wie bereits in Kapitel 9, »Grundlagen der Programmierung«, kurz erwähnt, wird das m vor dem Ausdruck in der Regel weggelassen. Es ist nur dann wichtig, wenn Sie statt des / ein anderes Zeichen verwenden, was besonders nützlich ist, falls der / selbst im regulären Ausdruck vorkommt. Sie können sämtliche Zeichen benutzen, die auch für Quoting-Operatoren wie q// oder qw// zulässig sind; in einem solchen Fall ist das vorangestellte m aber zwingend erforderlich. Beispielsweise können Sie folgendermaßen überprüfen, ob es sich beim Inhalt der Variablen $pfad um einen absoluten Unix-Pfad handelt:

print "Unix-Pfad!" if $pfad =~ m|^(/[^/]+)+|;

In der normalen Schreibweise wäre es erheblich komplizierter, diese Anweisung zu schreiben, und obendrein wäre sie viel schwerer lesbar:

print "Unix-Pfad!" if $pfad =~ /^(\/[^\/]+)+/;

Der Ausdruck bedeutet in beiden Fällen: Zu Beginn des Ausdrucks (^) steht ein Slash (/), gefolgt von einem oder mehreren Zeichen außer dem Slash ([^/]+). Diese Abfolge wiederholt sich bei Bedarf mehrere Male (+ außerhalb der Klammern). Im zweiten Fall wirkt es sehr störend, dass der Slash selbst nicht einfach verwendet werden kann, sondern durch einen vorangestellten Backslash zum normalen Zeichen erklärt werden muss.

Eine weitere Anwendungsmöglichkeit regulärer Ausdrücke ist das Ersetzen der jeweiligen Fundstellen durch einen Ersatztext. Dies geschieht in Perl mithilfe des Operators s///. Beispielsweise ersetzt die folgende Anweisung jedes Vorkommen von »Düsseldorf« oder »Leverkusen« in der Variablen $text durch »Köln«:

$text =~ s/(Düsseldorf)|(Leverkusen)/Köln/g;

Der bereits erwähnte Modifikator g sorgt dafür, dass jedes Vorkommen des gesuchten regulären Ausdrucks ersetzt wird.

Durch die Verwendung von Klammern im regulären Ausdruck können Sie außerdem die Speicherung einzelner Teile des gefundenen Textes veranlassen, diese Teile können Sie innerhalb des Ersatztextes verwenden. Beispielsweise könnten Sie eine Angabe von Postleitzahl und Ort nach dem Schema »53229 Bonn« in die Schreibweise »Postleitzahl: 53229, Ort: Bonn« umwandeln:

$ortsangabe =
s/((\d{5})\s+([a-z]+)/Postleitzahl: $1, Ort: $2/i;

Auch zum Extrahieren bestimmter Informationen aus einem Gesamttext sind die Platzhalter $1 bis $9 hervorragend geeignet. Zum Beispiel können Sie folgendermaßen den Inhalt der Textdatei info.txt nach Angaben durchforsten, bei denen es sich sehr wahrscheinlich um E-Mail-Adressen handelt:

open (FH, "<info.txt") || die "Kann nicht öffnen!\n";
while ($line = <FH>) {
chomp $line;
while ($line =~ /([a-z0-9\.\-_]+\@[a-z0-9\.\-_]+)/) {
push (@mails, $1);
}
}
close FH;
print "Gefundene Mail-Adressen:\n";
foreach $addr(@mails) {
print "$addr\n";
}

Der reguläre Ausdruck, der hier für E-Mail-Adressen verwendet wird, basiert auf einer Wahrscheinlichkeitsannahme und ist nicht absolut genau. Gefunden wird eine Sequenz aus Buchstaben, Ziffern, Bindestrichen und Unterstrichen, ein @-Zeichen und eine weitere Sequenz aus den genannten Zeichen. Einige Administratoren erlauben in E-Mail-Benutzernamen noch andere Zeichen, solche nicht standardkonformen E-Mail-Adressen bleiben unentdeckt. Außerdem würde beispielsweise ein Punkt hinter einer E-Mail-Adresse, die am Ende eines Satzes steht, mit aufgenommen.

Eine ähnliche Funktion wie s/// erledigt übrigens der Operator tr///, der Translations-Operator: Er ersetzt jedes Vorkommen des Strings im ersten Teil durch den String im zweiten Teil. Insofern hat er allerdings nichts mit regulären Ausdrücken zu tun.

Um in Ruby einen String mit einem regulären Ausdruck zu vergleichen, wird ebenfalls die Schreibweise

String =~ /Regexp/

verwendet. Das folgende Beispiel prüft, ob die String-Variable text HTML- oder XML-Code enthält (Text in spitzen Klammern):

if text =~ /<.+>/
puts "Text enthält HTML/XML"
end

Zum Ersetzen des ersten Vorkommens wird die Methode sub verwendet, für alle Vorkommen gsub. Beide Methoden stehen auch in einer Variante mit abschließendem Ausrufezeichen zur Verfügung, das die jeweilige Variable selbst manipuliert. Das folgende Beispiel entfernt alle HTML- oder XML-Tags dauerhaft aus der String-Variablen text:

text = "Hier ist <b>fetter</b> und </i>kursiver</i> Text"
text.gsub!(/<.+?>/, "")
puts text

Das Ergebnis lautet erwartungsgemäß »Hier ist fetter und kursiver Text«.

Eine interessante Besonderheit ist, dass Sie gsub mit einem Block aufrufen können, der beliebig komplexen Ruby-Code zum Erstellen des Ersatztextes enthalten kann. Der jeweilige Treffer wird dabei als Variable in den Block hereingereicht; der zuletzt verarbeitete Ausdruck im Block liefert den Ersatztext. Das folgende Beispiel ersetzt alle Ganzzahlen in einem Text durch ihre Hexadezimalentsprechung samt führendem 0x:

text = "256 Programmierer schreiben 1024 Programme in 32 Wochen.
Wie viele Programme schaffen 512 Programmierer in 64 Wochen?"
text.gsub!(/\b-?[0-9]+\b/) { |wert|
# Wert explizit in eine Zahl umwandeln
zahl = wert.to_i
# Hexadezimalstring berechnen
hexzahl = zahl.to_s(16)
# Rückgabwert
"0x#{hexzahl}"
}
puts text

Hier die Ausgabe (die Lösung dieser einfachen Dreisatz-Textaufgabe müssen Sie dagegen selbst berechnen; siehe dazu den betreffenden Abschnitt in Kapitel 2, »Mathematische und technische Grundlagen«):

0x100 Programmierer schreiben 0x400 Programme in 0x20 Wochen.
Wie viele Programme schaffen 0x200 Programmierer in 0x40 Wochen?



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück




Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de


  Zum Katalog
Zum Katalog: IT-Handbuch für Fachinformatiker






IT-Handbuch für Fachinformatiker
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: Linux Handbuch






 Linux Handbuch


Zum Katalog: Computer Netzwerke






 Computer Netzwerke


Zum Katalog: Schrödinger lernt HTML5, CSS3 und JavaScript






 Schrödinger lernt
 HTML5, CSS3
 und JavaScript


Zum Katalog: Windows 8.1 Pro






 Windows 8.1 Pro


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo