2.7 Operatoren
Bisher haben wir uns im Wesentlichen mit lauter einzelnen Daten beschäftigt. In diesem Abschnitt wollen wir nun Daten kombinieren. In diesem Zusammenhang werden die Daten Operanden genannt. Das oder die Zeichen, die sie verbinden, wird Operator genannt. Die Kombination aus beiden heißt Ausdruck. Tabelle 2.8 zeigt ein paar Beispiele.
Ausdruck | Operand | Operator | Operand |
intVar = 42 |
intVar |
= |
42 |
6 + intVar |
6 |
+ |
intVar |
Not True |
Not |
True |
Der Effekt eines Ausdrucks hängt von der Art des verwendeten Operators ab. Hier unterteilen wir die Operatoren in diese Gruppen:
- Arithmetische Operatoren
- Relationale Operatoren (Vergleichsoperatoren)
- Logische Operatoren
- Zuweisungsoperatoren
- Sonstige Operatoren
2.7.1 Arithmetische Operatoren
Visual Basic kennt neben den vier Grundrechenarten noch eine Division mit ganzzahligem Ergebnis und mit Rest sowie einen Minus- und einen Potenzoperator (siehe Tabelle 2.9).
Operator | Beschreibung |
+ |
Summe zweier Operanden (x + y; auch String, Date, DateTime) |
- |
Differenz zweier Operanden (x – y; auch Date, DateTime) negative Zahl (–x), einstelliger Präfixoperator |
* |
Produkt zweier Operanden (x * y) |
/ |
Quotient zweier Operanden (x / y) |
\ |
ganzzahliger Anteil des Quotients zweier Operanden (x \ y) |
Mod |
Rest einer ganzzahligen Division (x Mod y) |
^ |
potenziert eine Zahl mit einem Exponenten (x ^ y) |
Die vier Grundrechenarten und der Potenzoperator werden wie sonst üblich verwendet. Die Division gibt es in zwei zusätzlichen Variationen. Ist man nur am ganzzahligen Anteil interessiert, kommt der rückwärtige Schrägstrich \ zum Einsatz, während der Rest einer ganzzahligen Division von Mod geliefert wird. Zum Beispiel liefert 14\3 die ganze Zahl 4 und 14 Mod 3 ergibt 2. Das folgende Codefragment zeigt diese drei Divisionsarten in Aktion sowie eine Subtraktion zweier Datumsangaben.
' ...\Sprachsyntax\Operatoren\Operatoren.vb |
Option Strict On Namespace Sprachsyntax Module Operatoren ... Sub Arithmetik() Dim x As Integer = 14 Dim y As Integer = 3 Console.WriteLine("{0}/{1}: {2}", x, y, x / y) '4.666 Console.WriteLine("{0}\{1}: {2}", x, y, x \ y) '4 Console.WriteLine("{0} Mod {1}: {2}", x,y, x Mod y) '2 Console.WriteLine("{0}^{1}: {2}", x, y, x ^ y) '2744 Dim d1 As Date = Date.Now Dim d2 As Date = Date.UtcNow Console.WriteLine("Zeitzone: {0}", d1 – d2) '01:00:00 Console.ReadLine() End Sub End Module End Namespace
Der Operator \ ist besonders dann nützlich, wenn das Ergebnis der Division einer ganzzahligen Variablen zugewiesen werden soll oder eine Funktion eine ganze Zahl erwartet, zum Beispiel einen Index. Da das Ergebnis des Mod-Operators keine Rückschlüsse auf die Operanden zulässt, wird er in der Kryptografie verwendet. In einer Schleife kann er zum Beispiel verwendet werden, um eine Ausgabe nur für jeden 10. Wert eines Zählers zu machen, indem geprüft wird, ob zähler Mod 10 null ergibt.
Fließkommazahlen sind als Operanden für Mod auch erlaubt. Zum Beispiel ergibt 14.2 Mod 3.1 die Zahl 1.8.
Hinweis |
Im Gegensatz zu C# prüft Visual Basic standardmäßig, ob eine Operation den Rahmen eines ganzzahligen Zahlentyps sprengt (Überlauf). Dies kann in den zusätzlichen Compileroptionen geändert werden (Button Advanced Compile Options auf dem Register Compile der Projekteigenschaften). |
2.7.2 Relationale Operatoren
Relationale Operatoren vergleichen zwei Ausdrücke miteinander. Der Rückgabewert ist immer ein Boolean, also entweder True oder False. Vergleiche können auf Gleichheit bzw. Ungleichheit sowie auf größer und kleiner durchgeführt werden (True ist kleiner als False, "" und Nothing sind äquivalent). Tabelle 2.10 zeigt die Vergleichsoperatoren.
Operator | Beschreibung |
a = b |
True, wenn a gleich b ist |
a <> b |
True, wenn a ungleich b ist |
a > b |
True, wenn a größer b ist |
a < b |
True, wenn a kleiner b ist |
a <= b |
True, wenn a kleiner oder gleich b ist |
a >= b |
True, wenn a größer oder gleich b ist |
Like |
True, wenn eine Zeichenfolge einem Muster entspricht |
Is |
True, wenn beide Operanden dasselbe Objekt darstellen |
IsNot |
True, wenn beide Operanden nicht dasselbe Objekt darstellen |
TypeOf...Is |
prüft ein Objekt auf einen bestimmten Typ |
Das Gleichheitszeichen dient als Zuweisungs- und als Vergleichsoperator. Die Wahl des richtigen Operators ergibt sich nur aus dem Kontext. Es können auch zwei Objekte mit dem Is-Operator verglichen werden. Mit dem Vergleichsoperator TypeOf...Is prüft man ein Objekt auf seinen Typ. Die Tragweite dieser beiden Prüfungen wird später im Rahmen der Objektorientierung deutlich.
Der Vergleichsoperator Like vergleicht zwei Zeichenfolgen:
Dim bolStr As Boolean
bolStr = "Hallo" Like "hallo"
Das Ergebnis des Vergleichs wird False sein, weil sich die beiden Zeichenfolgeliterale im ersten Buchstaben unterscheiden. Visual Basic unterscheidet standardmäßig zwei Zeichenfolgen auf binärer Basis, differenziert also zwischen der Groß- und Kleinschreibung. Die Compileroption Option Compare Text überschreibt dieses Verhalten. Wie alle Compileroptionen kann sie am Anfang einer Datei stehen oder im Projekteigenschaftsfenster gesetzt werden, was sich dann anwendungsweit auswirkt. Die Standardeinstellung dieses Optionsschalters lautet Option Compare Binary.
Der Operator Like geht in seinen Möglichkeiten aber noch deutlich weiter: Er kann auch eine Zeichenfolge mit einem Zeichenfolgemuster vergleichen, das Platzhalter, Zeichenlisten und Zeichenbereiche in beliebiger Kombination enthalten kann (siehe Tabelle 2.11).
Zeichen | Beschreibung |
? |
Platzhalter für genau ein beliebiges Zeichen |
* |
Platzhalter für kein oder mehrere Zeichen |
# |
Platzhalter für eine Ziffer im Bereich 0–9 |
[<Zeichenliste>] |
Zeichenbereich für ein gesuchtes Zeichen in einer Zeichenfolge |
[!<Zeichenliste>] |
Ausschließenden Zeichenbereich für ein gesuchtes Zeichen in einer Zeichenfolge |
Dazu einige Beispiele:
'die folgenden Ausdrücke liefern alle "True" bolVar = "Hallo" Like "*al*" bolVar = "VB7" Like "VB#" bolVar = "7Uhr" Like "#[P-U][!c-e]*"
Das letzte Muster verlangt durch # eine Ziffer an der ersten Position der Zeichenfolge (7). An zweiter Position muss ein Zeichen stehen, das sich im Bereich zwischen einschließlich P und U bewegen muss (U). Das dritte Zeichen wiederum darf kein Zeichen zwischen c und e sein (h). Der Rest der Zeichenfolge kann in jeder Hinsicht beliebig sein (r).
2.7.3 Logische Operatoren
Logische Operatoren verknüpfen zwei Wahrheitswerte, um daraus einen kombinierten Wahrheitswert zu ermitteln. Die Operanden können sowohl Werte darstellen als auch aus Vergleichsoperationen gebildet werden. Tabelle 2.12 zeigt die logischen Operatoren.
In der Datenverarbeitung spricht man von:
- True, wenn ein Vergleich zutrifft, also wahr ist
- False, wenn der Vergleich nicht zutrifft, also falsch ist
Operator | Beschreibung |
And |
True, wenn beide Operanden True sind; beide Operanden werden geprüft. |
Or |
True, wenn mindestens einer der beiden Operanden True ist; beide Operanden werden geprüft. |
Xor |
True, wenn beide Operanden unterschiedliche Wahrheitswerte haben |
AndAlso |
Basiert auf dem And-Operator; liefert der erste Operand False, wird der zweite nicht mehr überprüft. |
OrElse |
Basiert auf dem Or-Operator; liefert der erste Operand True, wird der zweite nicht mehr überprüft. |
Not |
Logische Negation; kehrt einen Wahrheitswert um. |
Hinweis |
Benutzerdefinierte Typen können in Vergleichsoperationen verwendet werden, wenn sie implizit in Boolean oder Boolean? konvertiert werden können oder die Operatoren IsTrue und IsFalse definieren oder wenn die verwendeten Vergleichsoperatoren für den eigenen Typ definiert sind. |
Das Ergebnis logischer Operationen lässt sich am besten anhand einer Wahrheitstabelle darstellen (siehe Tabelle 2.13).
Bedingung 1 | Bedingung 2 | And | Or | Xor |
False |
False |
False |
False |
False |
True |
False |
False |
True |
True |
False |
True |
False |
True |
True |
True |
True |
True |
True |
False |
Beachten Sie bitte, dass es sich bei Operanden tatsächlich um Ausdrücke handelt, die boolesche Werte repräsentieren. Daher führt die folgende Anweisung zu einer Fehlermeldung:
'unzulässige boolesche Operation Dim bolVar As Boolean bolVar = 1 And 2
Beide Literale sind Integer, die nicht implizit in einen Boolean konvertiert werden können. Explizit ist dies möglich:
Dim bolVar As Boolean bolVar = CBool(1) And CBool(0)
Eine gültige boolesche Operation wäre beispielsweise:
x < 10 And y >= 12
Das Ergebnis ist nur dann True, wenn x eine Zahl kleiner 10 ist und gleichzeitig y entweder größer oder gleich 12 ist. Alle anderen Fälle ergeben False.
Ist nun x größer als 10, ist es gar nicht nötig, den zweiten Teil der And-Operation auszuwerten, da False And irgendwas immer False ergibt. Lassen Sie uns prüfen, ob dies dennoch erfolgt. Dazu simulieren wir die beiden Möglichkeiten eines Vergleichs (True oder False) in je einer Funktion, die außerdem zur Konsole schreibt, um festzustellen, ob dieser Teil einer booleschen Operation überhaupt ausgewertet wurde (zur Definition von Funktionen, siehe Abschnitt 2.5.8, »Funktionen«). Das folgende Codefragment enthält zum Vergleich beide Varianten der Und- sowie der Oder-Verknüpfung.
' ...\Sprachsyntax\Operatoren\Operatoren.vb |
Option Strict On Namespace Sprachsyntax Module Operatoren ... Function Ja() As Boolean Console.Write("Wahr ") : Return True End Function Function Nein() As Boolean Console.Write("Falsch ") : Return False End Function Sub Kurzschluss() Console.WriteLine("And", Nein() And Ja()) 'beide Console.WriteLine("AndAlso", Nein() AndAlso Ja()) 'erste Console.WriteLine("Or", Ja() Or Nein()) 'beide Console.WriteLine("OrElse", Ja() OrElse Nein()) 'erste Console.ReadLine() End Sub End Module End Namespace
Die Ausgabe zeigt, dass And und Or immer beide Teile auswerten, während AndAlso und OrElse nur so lange wie nötig auswerten. Dies wird auch als Kurzschluss bezeichnet. Man kann sich also niemals darauf verlassen, dass der rechte Operand dieser Verknüpfungen ausgeführt wird.
Falsch Wahr And Falsch AndAlso Wahr Falsch Or Wahr OrElse
Oft ist eine vollständige Auswertung ärgerlich, zum Beispiel bei einer Division:
x<>0 AndAlso 1/x<0.1
Hinweis |
In jedem Programm sollten logische Operationen möglichst so formuliert werden, dass der Programm-ablauf nicht davon abhängt, dass alle Operanden ausgewertet wurden. |
Der Not-Operator kehrt das Ergebnis einer logischen Operation um:
Dim Zahl As Long ... Dim bolValue As Boolean bolValue = Not (Zahl > 5)
liefert dann True für bolValue, wenn Zahl gleich oder kleiner 5 ist.
Hinweis |
Bei nullbaren Typen (siehe Abschnitt 4.5, »Werttypen mit dem Wert Nothing«) wird Nothing als Ergebnis einer Vergleichsoperation erzeugt, wenn ein Operand Nothing ist und der andere das Ergebnis nicht allein festlegen kann. Ist der erste Operand Nothing, wird der zweite auch in AndAlso und OrElse immer ausgewertet. |
2.7.4 Bitweise Operatoren
Häufig kann ein Zustand eines Objekts nur wenige Werte annehmen. Will man viele solcher Zustände speichern, ist es eine ziemliche Verschwendung, für jeden Zustand eine eigene Variable zu verwenden. Man kann sich vielmehr den Umstand zunutze machen, dass jede Variable als Bitmuster im Speicher liegt, und die Bits einzeln auswerten oder verändern. Zum Beispiel besteht ein Integer aus 32 Bit und kann 32 An/Aus-Zustände speichern. Diese Möglichkeiten werden an vielen Stellen innerhalb des .NET Frameworks verwendet. Tabelle 2.14 zeigt alle Operatoren, die auf einzelnen Bits agieren.
Operator | Beschreibung |
>> |
Bitmuster nach rechts schieben |
<< |
Bitmuster nach links schieben |
And |
Bit setzen, wenn beide Operanden das Bit gesetzt haben |
Or |
Bit setzen, wenn mindestens ein Operand das Bit gesetzt hat |
Xor |
Bit setzen, wenn nur ein Operand das Bit gesetzt hat |
Not |
Bits alle umkehren |
Ein gutes Beispiel ist die Erkennung, welche Tasten der Tastatur gedrückt wurden. Jeder Taste entspricht eine Zahl. Im Modul ConsoleModifiers sind den Tasten , und diese Zahlen zugewiesen worden:
Taste | Wert | Bitmuster |
|
1 |
0000 0001 |
|
4 |
0000 0100 |
|
2 |
0000 0010 |
Wollen wir nun überprüfen, ob die -Taste gedrückt wurde, müssen wir testen, ob das Bit 2 (22 = 4) gesetzt ist. Hierfür bietet sich die bitweise Verknüpfung mit dem And-Operator an. Das Ergebnis hat nur dort ein Bit gesetzt, wo beide Operanden ein gesetztes Bit haben. Nehmen wir nun an, der Tastaturcode sei 21. Damit ergibt sich:
0001 0101 And 0000 0100 ------------- 0000 0100
Wenn also das Ergebnis der Kombination größer als null ist, ist das Bit in der zu testenden Zahl gesetzt.
(21 And 4) > 0
Die Klammern müssen gesetzt werden, da sonst der Ausdruck implizit so geklammert würde:
21 And (4 > 0) 'Fehler!!
Dieser Ausdruck würde versuchen, mit dem And-Operator eine Zahl und einen Wahrheitswert zu kombinieren. Dies ist nicht definiert und führt zu einer Fehlermeldung des Compilers.
Eine Alternative zu And bietet Or, das dann ein Bit setzt, wenn in einem der beiden Operanden das Bit gesetzt ist. Für unser Beispiel heißt das:
0001 0101 Or 0000 0100 ------------ 0001 0101
Verändert die Verknüpfung die Zahl nicht, ist sie exakt gleich dem zweiten Operanden. Da hier außer den Modifikatortasten noch die Zahl 16 im Tastaturcode steckt, sollte dieser Anteil vor dem Test abgezogen werden. Die folgende Zeile prüft also, ob ausschließlich die -Taste gedrückt ist. Die außerdem gedrückte -Taste verändert die Zahl.
(21-16 Or 4) = 4 'False
Or kann auch genutzt werden, um zu testen, ob entweder die -Taste oder die -Taste oder beide gedrückt wurden. Der Test prüft, ob das Bit 0 oder 2 gesetzt ist. Die Kombination dieser Bitmuster ist einfach mit dem Or-Operator möglich. Damit lautet die Prüfung:
(21 And (1 Or 4)) > 0
Ein weiterer Test ist zum Beispiel, ob die -Taste nicht gedrückt ist. Hierbei hilft der Not-Operator. Er kehrt alle Bits um.
Not 0001 0101 ------------- 1110 1010 And 0000 0100 ------------- 0000 0000 (Not 21 And 4) = 0
Der Xor-Operator setzt dann ein Bit, wenn die Bits beider Operanden verschieden sind. Zum Beispiel kann er die -Taste aus der Kombination von + herausfiltern.
0000 0101 Xor 0000 0100 ------------- 0000 0001
Bitschiebeoperationen verschieben ein Bitmuster nach links oder rechts, was für positive Zahlen einer sehr effizienten n-fache Multiplikation oder Division mit der Zahl 2 entspricht. Bei Rechtsschiebung negativer Zahlen wird zusätzlich vorher 1 addiert und danach 1 abgezogen. Der rechte Operand der Operation ist immer der Modulus der Bitbreite der zu schiebenden Zahl. In den beiden folgenden Zeilen wird die Zahl 21 mit 27 multipliziert bzw. durch 23 dividiert (und abgerundet).
21 << 7 '2688 21 >> 4 '1
2.7.5 Verkettungsoperator
Wollen Sie, während das Programm läuft, eine Zeichenkette aus mehreren Teilen zusammensetzen, können Sie die Teile mit dem &-Operator verketten.
"Jetzt schlägts " & Now.Hour & "!"
In der Verkettung dürfen alle Datentypen verwendet werden, die sich implizit in eine Zeichenkette umwandeln lassen, wie zum Beispiel alle primitiven Datentypen. Benutzerdefinierte Typen müssen eine erweiternde Konvertierung definieren.
Da alles in .NET ein Objekt ist und jedes Objekt die Methode ToString() hat, kann mit <wert>.ToString() jedes Objekt verkettet werden. Diese Umwandlung erzeugt für Zahlen das Gewünschte. Für andere Daten kann die Art der Information gegebenenfalls nicht hilfreich sein. So wird zum Beispiel Nothing als Leerstring "" eingebunden, macht sich also gar nicht bemerkbar, während ein Datenbankwert und ein nullbarer Typ gegebenenfalls "Nothing" erzeugen.
Hinweis |
Eine Verkettung ist auch mit + möglich. Da Plus aber für einige Daten, wie zum Beispiel Zahlen, eine besondere Bedeutung hat, kommt es dann zu einem Syntaxfehler. Deshalb sollte immer & zur Verkettung benutzt werden. |
2.7.6 Zuweisungsoperatoren
Visual Basic hat neben dem normalen Zuweisungsoperator viele Varianten, die eine Operation mit einer Zuweisung verknüpfen. Im Gegensatz zu der langen Formulierung in der dritten Spalte von Tabelle 2.15 wird x nur einmal ausgewertet, was die Operationen unter anderem schneller macht.
Operator | Beipiel | Effekt (x wird nur 1 mal ausgewertet) |
= |
x = y |
x wird der Wert von y zugewiesen |
+= |
x += y |
x = x + y |
-= |
x -= y |
x = x – y |
*= |
x *= y |
x = x * y |
/= |
x /= y |
x = x / y |
\= |
x \= y |
x = x \ y |
^= |
x ^= y |
x = x ^ y |
<<= |
x <<= y |
x = x << y |
>>= |
x >>= y |
x = x >> y |
&= |
x &= y |
x = x & y |
Mid |
Mid(x,2,3) = y |
Ersetze Zeichen 2 bis 4 durch y. |
Links vom Gleichheitszeichen muss eine Variable stehen und kein Wert. Da eine Funktion einen Wert zurückliefert, scheitert die folgende Zuweisung:
Function val() As ConsoleColor Return Console.ForegroundColor End Function Sub Zuweisung() val() = ConsoleColor.Cyan 'Fehler, da Wert End Sub
Der einfache Zuweisungsoperator unterscheidet sich formal nicht vom Vergleichsoperator. Nur aus dem Kontext heraus erfolgt eine Unterscheidung. Der Ausdruck
a = b = c
weist nicht den Inhalt von c erst b zu und danach a, sondern
b = c
wird als Vergleich interpretiert, der einen booleschen Wert, True oder False, zurückliefert. Erst nach der Vergleichsoperation wird dessen Ergebnis der Variablen a zugewiesen, die vom Typ Boolean sein muss.
Zeichenketten haben den zusätzlichen Operator Mid, um Textteile zu ersetzen. Das folgende Codefragment liefert »1abc5« als Ergebnis. Die Anweisung lautet: Starte mit Zeichen 2, und ersetze 3 Zeichen durch Zeichen auf der rechten Seite (oder bis die rechte Seite »aufgebraucht« ist).
Dim s As String = "12345" Mid(s, 2, 3) = "abcdefg"
Hinweis |
Ist der Wert einer Zuweisung nicht implizit in den Typ der Variable (oder Eigenschaft) konvertierbar, kommt es zu einem Compiler- oder Laufzeitfehler. |
2.7.7 Operatorprioritäten
Enthalten Ausdrücke mehrere Operatoren, werden diese in einer festgelegten Reihenfolge ausgewertet. Je höher die Priorität eines Operators ist, desto stärker bindet er die Operanden. In Tabelle 2.16 steht ein höher priorisierter Operator weiter oben.
Innerhalb der Teilausdrücke werden alle Operatoren gemäß ihrer Priorität behandelt. Bei gleicher Priorität wird von links nach rechts ausgewertet (auch Zuweisungen). Falls Sie sich bei einigen Operatoren über die Priorität unsicher sind, dann sollten Sie sicherheitshalber Klammern verwenden.
Operator | Beschreibung |
() |
Gruppierung |
^ |
Exponentialoperator |
- |
hier: Negation |
*, / |
Multiplikation, Division |
\ |
ganzzahlige Division |
Mod |
Restwertdivision |
+, - |
Addition, Subtraktion |
& |
Stringverkettung |
<<>> |
Bitschiebeoperatoren |
=, <>, <, >, <=, >=, TypeOf ...Is, Is, Like |
Vergleiche |
Not |
Negation |
And, AndAlso |
logisches/bitweises Und |
Or, OrElse |
logisches/bitweises Oder |
Xor |
exklusives Oder |
= += -= *= /= \= ^= <<= >>= &= |
Zuweisung |
Hinweis |
Benutzerdefinierte Operatoren haben Vorrang. Analog werden bei konkurrierenden Definitionen nicht nullbare Typen und, bei einem Import aus anderen Sprachen, bitweise Operatoren (mit Vorzeichen) bevorzugt. |
2.7.8 Zusammenfassung
- Arithmetische Operatoren werden für alle vier Grundrechenarten bereitgestellt. Dazu kommt ein weiterer Operator für die Potenzierung. Für die Division stehen insbesondere drei Operatoren zur Verfügung, die den Dezimalteil einer Division beibehalten, ihn abschneiden oder auch nur den ganzzahligen Rest der Operation liefern.
- Bei den mathematischen Operationen ist zu berücksichtigen, dass der Compiler ungekennzeichnete Literale als Integer bzw. Double interpretiert.
- Relationale Operatoren (Vergleichsoperatoren) vergleichen zwei Ausdrücke miteinander und liefern einen booleschen Wert.
- Logische Operatoren verbinden zwei Wahrheitswerte und liefern als Ergebnis wiederum einen Wahrheitswert zurück.
- Die Operatorpaare And und AndAlso sowie Or und OrElse unterscheiden sich im Prüfverhalten. Mit And und Or werden die beiden am Vergleich beteiligten Operanden in jedem Fall geprüft, mit AndAlso und OrElse wird auf die Prüfung des rechten Operanden verzichtet, wenn dessen Prüfergebnis keinen Einfluss auf das Resultat der gesamten Operation hat.
- Die Operatoren And, Or und Xor können sowohl für Vergleichsoperationen als auch für bitweise Operationen eingesetzt werden.
- Innerhalb eines Ausdrucks, der einen Wahrheitswert zurückliefert, wird das Gleichheitszeichen als Vergleichsoperator interpretiert, ansonsten als Zuweisungsoperator. Nur aus dem syntaktischen Zusammenhang heraus lässt sich Funktionalität erkennen, die auch Konsequenzen hinsichtlich der Priorität nach sich zieht.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.