Programmieren mit Python

Reguläre Ausdrücke

Nachdem unser Tischrechner jetzt schon sehr gut funktioniert, und ihn der eine oder andere vielleicht sogar produktiv benutzt, im folgenden eine Warnung.

WARNUNG(!) ERNSTHAFTE WARNUNG:

Manche Provider (zum Erstellen von Web-Seiten) erlauben auch Python als Programmiersprache - mein Provider leider nicht. Wir haben in unserer Einführung die "Zauberfunktion" "eval()" benutzt. Die ist natürlich sehr praktisch und leistungsfähig. Verwenden Sie diese Funktion NIEMALS für Programme, die Sie in einer Webseite oder anderen Anwendungen verwenden, auf die man von außen (dem Internet) zugreifen kann. Diese Funktion erlaubt beliebige Python-Ausdrücke. Ein "Angreifer" kann das BRUTAL ausnutzen, um Ihr System zu kompromittieren(!). In unserem kleinen Beispiel (Tischrechner) verwenden wir das nur lokal. Sie sollten den Tischrechner auch nur in Verzeichnissen speichern, auf die man von außen (dem Internet) keinen Zugriff hat(!). Das ganze gilt erst recht für die die noch weitergehende Funktion exec(), die wir später noch verwenden werden(!).

Nach dieser Warnung fangen wir jetzt mit der Großen Schweinerei an ;-) Dazu benötigen wir aber vorab noch etwas neues, was aber nicht Python-spezifisch ist. Gute Textverarbeitungssysteme z. B. unterstützen auch Suche mit regulären Ausdrücken.

Unser Tischrechner kann jetzt schon fast alles was mein „Coca” kann (sogar mehr, mein Coca unterstützt keine komplexen Zahlen). Aber eines kann er noch nicht:

Variablen.

Was sind Variablen?

Bei meinem "Coca" können sie z. B. folgendes machen:

Mwst=1.19

und dann den Bruttobetrag mit z. B.:

437*Mwst

berechnen. "Mwst" (Groß-/Kleinschreibung MUSS beachtet werden!) ist eine Variable, also wie ein Speicher (M) bei einem Taschenrechner, in dem Sie beliebige Werte speichern können. Um das in unseren Tischrechner einbauen zu können, müssten wir in den Parser eingreifen können. Da wir als Parser aber die Zauberfunktion "eval()" verwenden, haben wir da keine Chance. Also müssen wir das anders lösen. Es gibt verschiedene Möglichkeiten, ich habe mich für die Version mit "Regulären Ausdrücken" entschieden.

Was ist ein Regulärer Ausdruck?

Ein regulärer Ausdruck ist ein Muster für eine bestimmte Zeichenfolge. Am besten erklärt mit einem Beispiel. Wir wollen das "Muster":

beliebige Zeichen@beliebige Zeichen "erkennen", also z. B. ein Muster wie:

Mein_Name@Meine_Domain

z. B: hans.dampf@meinedomain.de

Der reguläre Ausdruck, um so ein Muster zu erkennen lautet:

.+@.+

Erklärung:

'.' steht für irgend ein Zeichen und '+' bedeutet, dass so ein (BELIEBIGES) Zeichen mindestens einmal vorkommen muss, aber beliebig oft wiederholt werden darf.

Dann muss aber irgendwann das Zeichen '@' kommen und danach wieder (mindestens) ein beliebiges Zeichen (nach diesem dürfen wieder beliebig viele Zeichen folgen).

Ich hoffe, Sie haben das Prinzip verstanden. Genau müssen Sie das zum Glück gar nicht wissen, denn wenn Sie einen bestimmten regulären Ausdruck benötigen, können Sie diesen meist "Googlen". Z. B: ein regulärer Ausdruck für eine E-Mail-Adresse (damit sie zumindest formal der Syntax für E-Mail-Adressen entspricht):

Ich habe auf Google folgende Suche eingegeben:

python regular expression for e-mail

Und habe (glaube als dritten Eintrag) folgendes gefunden:

99,99% funktionierender regulärer Ausdruck für E-Mail-Adressen (Warnung: Dieser Link scheint hin und wieder nicht zu funktionieren; im Moment [2023-10-11] geht er wieder).

Wenn Sie auf dieser Seite nach unten scrollen, kommen für verschiedene Programmiersprachen fertig angepasste Versionen, des regulären Ausdrucks. Verwenden Sie einfach den für Python (copy and paste).

Es ist ganz wichtig beim „Programmieren”, dass Sie nicht immer wieder alles neu erfinden(!). Googlen Sie!

Folgende Syntax soll unser Tischrechner unterstützen, um eine Variable anzulegen:

Variable = beliebiger Ausdruck

Dazu benötigen wir jetzt einen regulären Ausdruck, der dieses Muster überprüft. Das "=" darf ja in einem normalen Ausdruck nicht vorkommen.

Auf folgendes bin ich selbst gekommen:

(?P<assign>^[A-Za-z][A-Za-z0-9]*\s*=)

Die umschließenden Klammern () bedeuten, dass der ganze Ausdruck eine Gruppe ist (wäre hier vermutlich gar nicht notwendig gewesen), das ?P<assign> benennt diese Gruppe, damit man später diese Gruppe mit dem Namen "assign" zuweisen kann. Das ^ bedeutet, dass das Muster nur am Anfang einer Zeichenfolge gefunden wird. Zwischen [...] werden Zeichen eingeschlossen, die erlaubt sind: z. B. [123] würde. die Zeichen 1, 2 und 3 erlauben, käme an dieser Stelle ein anderes Zeichen, würde das Muster nicht gefunden. Praktischerweise darf man das Minus-Zeichen verwenden um ganze Klassen einzuschließen. [A-Z] erlaubt also alle Großuchstaben (keine Umlaute, zumindest nicht wenn man mit ANSI-Codierung arbeitet). Ein Asterisk (*) hinter einem Zeichen oder Zeichenklasse bedeutet, dass das vorstehende Element 0 mal oder beliebig oft auftreten darf. Das „\s” steht für "Whitespace"-Zeichen (Leerzeichen, Tabulatoren, ...). Die erlaubte Syntax für Variablennamen, die unser Tischrechner akzeptiert ist also:

Muss mit Buchstaben beginnen, danach dürfen beliebig viele Buchstaben oder Ziffern folgen. Benutzerfreundlich wie wir sind, erlauben wir, dass vor und nachdem und dem Zuweisungszeichen „=” beliebiger Leerraum (z. B. Leerzeichen) eingefügt werden darf (Beispiele: Mwst19, Mwst7 = 7.0 aber auch(!): Kreisumfang = durchmesser * pi [dazu muss natürlich vorher die Variable durchmesser definiert worden sein; pi – die Kreiszahl – ist beim Start automatisch definiert. ACHTUNG: pi ist eine normale Variable! KEINE KONSTANTE! Man kann die Variable pi jederzeit mit einem eigenen Wert überschreiben! Also pi=3 ist erlaubt, danach ist pi nur noch die ungefähre Kreiszahl ;-); das gleiche gilt für e – die Eulersche Zahl – die ist auch automatisch definiert.]). (Ich habe jetzt etwas vorgegriffen, Variablen kann unser Rechner noch gar nicht, kommt jetzt:)

Im nächsten Kapitel bauen wir Variablen in unseren Parser mit Hilfe der "Großen Schweinerei" ein. Außerdem werden wir aus dem Parser-Modul eine Klasse machen (objektorientierte Programmierung).