19. String-Literale

Ein Literal ist die Repräsentation eines Wertes im Programm-Quellcode. So steht 138 in Python beispielsweise für die Zahl 138 – speichert der Rechner diese Zahl, stehen im Speicher nicht die Ziffern 1,3 und 8, sondern eher etwas wie 10001010 – wobei auch das nur eine Repräsentation für ein paar Sammlungen von Elektronen ist. Während nun 138 das Literal für diese Zahl (als abstraktes Konzept) in Python ist, könnten andere Sprachen da andere Vereinbarungen treffen und etwa 8a für unsere 138 verwenden, und auch Python erlaubt, die 138 im Programmtext also 0x8a oder auch str("138") darzustellen. Die interne Repräsentation ist jedoch in allen Fällen gleich (also in diesem Fall 10001010).

Strings können in Python-Quellcode auf verschiedene Arten dargestellt werden:

  1. in einfachen () und doppelten (") Anführungszeichen
  2. in dreifachen doppelten (""") oder einfachen (’’’) Anführungszeichen

Dabei gehen die Möglichkeiten bei (1) nur für einzeilige Strings, während (2) Strings zulassen, die über mehrere Zeilen gehen.

Das kann kombiniert werden mit zwei Modifikatoren, die jeweils vor die öffnenden Anführungszeichen geschrieben werden:

  • r für raw strings
  • u für unicode strings

Dabei werden in raw strings keine Escapes ausgewertet, während Unicode-Literale zu Unicode-Strings führen.

Die raw strings werden vor allem für reguläre Ausdrücke nützlich werden, während ihr Unicode-Literale vor allem braucht, um Unicode-Strings so zu manipulieren, dass sie auch Unicode-Strings bleiben.

Escape-Sequenzen

Wenn man in einem String Zeichen haben will, die z.B. für den Editor oder Python eine spezielle Bedeutung haben (Backspace, Return, Quotes) oder die man über die Tastatur nicht eingeben kann, kann man Escape-Sequenzen verwenden.

Escape-Sequenzen haben weder mit Sequenzen im Python-Sinn noch mit der Escape-Taste viel zu tun (und schon gar nichts mit Flucht, auch wenn manche Leute deutsche Übersetzungen in der Art von “Fluchtsymbol-Darstellung” machen). In ihnen steht einfach ein Backslash vor einem oder mehreren anderen Zeichen. Python ersetzt dann, wenn es (normalerweise zur Compilezeit) das Stringliteral auswertet, die Zeichen der Escape-Sequenz durch ein anderes Zeichen.

Gebräuchliche Escape-Sequenzen:

\n   Zeilenvorschub
\r   Wagenrücklauf
\"   Ein doppeltes Anführungszeichen
\b   Backspace
\t   Tab
\\   Backslash

Wörter wie Zeilenvorschub oder Wagenrücklauf (line feed bzw. carriage return) kommen offensichtlich aus der Zeit der Fernschreiber. Ihre Wirkung ist aber auch heute noch mehr oder minder so wie damals: Ein Zeilenvorschub lässt den Cursor in die nächste Zeile gehen, ein Wagenrücklauf bewegt ihn zurück an den Anfang der Zeile. Wenn ihr auf einem nicht ganz dämlichen System seid, werdet ihr allerdings feststellen, dass ein einfacher Zeilenvorschub den Cursor auf den Anfang der nächsten Zeile setzt. Das liegt an interner Magie des Betriebssystems, das nach der Ausgabe eines Zeilenvorschub einen Wagenrücklauf “reinzaubert”, wenn es das Ziel der Ausgabe für einen Textbildschirm hält. Bei Druckern wirkt diese Magie nicht, und deshalb findet man dort manchmal interessante Treppeneffekte.

Der Backspace lässt den Cursor um einen Schritt zurückgehen. Wenn euer System einen vernünftigen Terminalemulator hat, sollte etwa folgendes passieren:

>>> print "Welt\bd\rG"
Geld

In Summe:

>>> print 'bla', "romp", """Ein
...   ziemlich
... langer String"""
bla romp Ein
  ziemlich
langer String
>>> print "ein\nEscape", r"kein\nEscape"
ein
Escape kein\nEscape

Encoding des Quelltexts

Seit Python 2.3 unterstützt Python auch offiziell Quelltexte in verschiedenen Encodings. Ihr könnt auf diese Weise in euren Quelltext Unicode-Stringliterale einbetten, etwa

  someStr = u"Nüfbö"

Wüsste Python nicht um das Encoding des Quelltextes, könnte es die Umlaute nicht in einen Unicode-String übersetzen, denn dort kann nicht einfach irgendeine Zahl stehen, es muss etwas wie “hier steht ein ü” gespeichert sein. Das ü, das der Editor auf eurem System anzeigt, könnte aber woanders ein ø oder irgendein anderes wildes Zeichen sein, und Python kann nicht wissen, was für einen Editor ihr verwendet habt (bzw. welches Encoding euer Editor) – es sei denn, ihr würdet es ihm sagen.

Deshalb kann man das Encoding deklarieren. Die Art, in der Python das macht, ist nicht unumstritten – man schreibt nämlich

# -*- coding: iso-8859-1 -*-

in die erste oder zweite Zeile des Skripts. Umstritten ist das, weil auf diese Weise ein Kommentar die Semantik des Programms ändert, während eigentlich ein Kommentar doch definiert ist dadurch, dass er an der Semantik nichts ändert. Dass dem hier doch so ist, liegt am Sieg der PragmatikerInnen unter den Menschen, die Python weiterentwickeln, und daran, dass der verbeitetete Editor emacs diese Angabe automatisch versteht.

Kehrseite der an sich guten Einrichtung, das Encoding des Quelltexts definieren zu können ist, dass Python jetzt Warnungen ausgibt, wenn ihr Umlaute in String-Literalen verwendet (und vermutlich irgendwann einen Fehler). Das bedeutet im Effekt, dass eine coding-Angabe jetzt Pflicht ist, sofern euer Skript sich nicht auf reines ASCII beschänkt.

Das iso-8859-1 oben ist natürlich nur ein Beispiel. Ihr kommt nicht drumrum, herauszufinden, welches Encoding euer Editor verwendet. Auf unseren Poolmaschinen stimmt das iso-8859-1, es sei denn, ihr habt etwas anderes bestellt, unter neueren Windows-Versionen, unter BeOS, Mac OS X oder auf geeignet manipulierten Linux-Systemen kann (muss aber nicht) es sein, dass ihr schon utf-8 angeben müsst.

Übungen zu diesem Abschnitt

Ihr solltet euch wenigstens an den rötlich unterlegten Aufgaben versuchen

(1)

Um zu verstehen, wie das mit den Escape-Sequenzen geht, sieht man sich am besten die Zeichen an, die nachher in den Strings stehen, und zwar genauer deren Codes, d.h. die Zahlen, die der Rechner intern zur Repräsentation der Zeichen verwendet. An diese Zahlen kommt ihr über die eingebaute Funktion ord heran. Schreibt also einfach mal verschiedene Strings in ein Programm der folgenden Art und versucht zu verstehen, was passiert. Wie sind die Längen der Strings, die ihr probiert?

for ch in "a\tb\r\n\\":
  print  repr(ch), ord(ch)

Anmerkung: Die Funktion repr gibt die so genannte Repräsentation ihres Arguments zurück. Bei Strings bedeutet das, dass nicht druckbare Zeichen wieder als Escape-Sequenzen geschrieben werden. Probiert aus, was passiert, wenn ihr das repr weglasst.

(2)

Die split-Methode von Strings trennt ohne weitere Argumente an “irgendwelchen” Leerzeichen trennen. In der Tat sind für split auch Tabs, Zeilenvorschübe und Wagenrückläufe Leerzeichen (genauer: white space). Seht euch das folgende Beispiel an:

>>> s = "Some\tcrazy\nstring\rstuff here"
>>> s
>>> print s
>>> s.split()
>>> s.split(" ")

(3)

Die Funktion eval nimmt einen String, in dem ein Python-Ausdruck steht und tut das, was der Interpreter täte, wenn er diesen String sehen würde:

>>> eval("5+6")
11

Insbesondere wertet er innerhalb des Strings auch String-Literale aus. Damit kann man lustige Spiele treiben. Seht euch die folgenden Ausdrücke an und überlegt euch, was wohl ihr Wert sein wird. Seht nach, ob ihr recht hattet. Es ist natürlich möglich, dass da auch mal SyntaxErrors kommen

eval("'ab'")
eval('\'ab\'')
eval('\'ab\t\'')
eval(r"'ab\n'")
eval("r'ab\n'")
eval(eval("'\"ab\"'"))

Schafft ihr es, das letzte Beispiel um noch ein eval weiterzuspinnen?


Markus Demleitner

Copyright Notice