5. Zeichenketten

Auch wenn Zahlen bislang überzeugen konnten, arbeitet man doch mehr mit Zeichenketten. Der Umgang mit Zeichenketten (Datentyp str) zählt zu den Grundfertigkeiten aller Programmiersprachen.

Während viele Programmiersprachen den Teilzugriff auf Zeichenketten relativ umständlich konzipiert haben, so macht Python Ihnen hier die arbeit sehr leicht.

Da Zeichenketten an sich ein extrem grosses Kapitel darstellt, der Platz dafür aber nicht vorhanden ist, versuche ich Ihnen die wichtigsten Features der Zeichenketten zu erläutern.

5.1. Grundregeln

Zeichenketten werden im Code mit einfachen  ‚  oder  “  geschrieben. Sollen diese über mehrere Zeilen gehen, so muss statt der einfachen Apostrophe eine dreifache Apostrophe  “‘  bzw.  „““  benutzt werden.
Beide Varianten sind gleichwertig.

s = 'abc'
type(s)                               # Ausgabe: <class 'str'>

# Lange Zeichenkette
s = """Das ist 
    eine lange
    Zeichenkette"""
print(s)

Natürlich könnte man auf die Leerzeichen in der 2. und 3. Reihe vollkommen verzichten, da die Zeichenkette innerhalb eines dreifachen Apostrophs steht. Dann sähe der Code in etwa so aus:

if True:
    s = """Das ist
    eine lange
    Zeichenkette"""
print(s)

Aber: Wenn mir jemand diesen Code vorlegen würde, ich würde diesen steinigen.Es sieht nicht nur grauenhaft aus, sondern zerstört die optische Struktur.

5.1.1. Zeichenketten aneinanderfügen und vervielfältigen

Mit dem Operator  + fügen Sie Zeichenketten zusammen. Der Operator  *  vervielfacht Zeichenketten

s1 = 'abc
s2 = "efg"
s3 = s1 + s2 + s1            # Ausgabe: 'abcefgabc'
s4 = s1*3 + 'x'*2            # Ausgabe: 'abcabcabcxx'

5.1.2. Sonderzeichen

Zeichenketten werden intern in Unicode dargestellt. Bei Codedateien nimmt der Python Interpreter standardmässig an, das Sie in UTF-8 Codierung vorliegen. Ist dies nicht der Fall, kann die tatsächliche Codierung in der zeiten Zeile des Scripts in folgender Form angegeben werden.

# -*- coding: <encoding name> -*-
# Beispiel:
# -*- coding: latin-1 -*-

In Zeichenketten können mit  \  markierte Sonderzeichen eingebettet werden. Dies nennt man Escape Sequenzen. Ein paar dieser Escape Sequenzen werde ich in der unteren Tabelle darstellen.

ZeichensequenzBedeutung
\aSignalton
\fFormfeed (neue Seite)
\nZeilenumbruch
\rWagenrücklauf (für Windows Textdateien)
\tTabulatorzeichen
\unnnnUnicode Zeichen mit dem Hexcode &xnnnn
\‘das Zeichen ‚
\“das Zeichen „
\das Zeichen \
s = "Erste\nzweite\ndritte Zeile."
print(s)

# Ausgabe:
# Erste
# zweite
# dritte Zeile.

5.1.3. Raw Zeichenketten

Python hat die Angewohnheit Escape Zeichen als Sonderzeichen zu erkennen. Möchte man dieses nicht, oder man muss aufgrund der Vorgaben auf Escape Sequenzen verzichten, so kann man diese als Raw Zeichenketten benutzen. Dazu stellt man vor den entsprechenden Buchstaben ein  r‘  voran.

latexcode = r'\section{Überschrift}

Der im Beispiel angegebene latexcode ist ein Beispiel, wenn man ein Buch schreiben möchte. Dazu benutzt man z.B. das Programm „Latex“ oder „Miktex“

5.1.4. „chr“ und „ord“ Funktionen

Die Funktion chr liefert ein Zeichen, das dem übergebenen ASCII-Code bzw. Unicode entspricht.

chr(65)             # liefert 'A'
chr(8364)           # liefert '€'

Die Umkehrfunktion ord liefert aus dem übergebenen ASCII-Code bzw. Unicode das einzelne Zeichen. Wenn mehrere Zeichen übergeben werden, wird ein Fehler ausgeworfen.

ord('A')            # liefert 65
ord('€')            # liefert 83634
ord('abc')          # Typerror, expteted a character

5.2. Zugriff auf Teilzeichenkette

Damit Sie auf Teile einer Zeichenkette zugreifen können, benutzen wir die sogenannte Slicing Syntax. s[n] gibt die Position an, welches Zeichen zurückgegeben werden soll.

Es ist aber zu beachten, das n = 0 das erste Zeichen darstellt. Mit s[start:ende] liefert diese alle Zeichen zwischen start (inklusive) und ende (exklusive) zurück. Negative Werte geben den offset vom Ende der Zeichenkette an.

Verglichen mit anderen Programmiersprachen ist diese Syntax genial einfach und praktisch

s = 'abcdefghijklmnopqrstuvwxyz'
s[3]                    # liefert das vierte Zeichen
                        # (beginnend bei 0) also d
s[3:6]                  # liefert 'def'
s[:3]                   # liefert 'abc'
s[3:]                   # liefert 'defghijklmnopqrstuvwxyz'
s[-4]                   # liefert 'w'
s[-4:]                  # liefert 'wxyz'

5.2.1. IndexError

Wenn Sie in der Slicing Schreibweise Indizes angeben, die die Länge der Zeichenkette überschreiten, dann tritt ein Fehler auf.

s = 'abcdefghijklmnopqrstuvwxyz'
s[25]                   # OK, letztes Zeichen
s[-1]                   # OK, letztes Zeichen
s[26]                   # Fehler, IndexError: string index out of range
s[-26]                  @ OK, erstes Zeichen
s[-27]                  # Fehler, IndexError: string index out of range

5.2.2. Schrittweise (Stride)

Durch einen dritten Parameter (dem Stride Parameter) kann eine Art Schrittweite angegeben werden, Beispiel: s[start;ende:schrittweite]. Da alle Parameter optional sind, ergeben sich viele interessante Varianten.

s = 'abcdefghijklmnopqrstuvwxyz'
s[::2]                  # jedes zweite Zeichen
s[:10:2]                # von den ersten 10 Zeichen jedes 2.
s[10::2]                # ab dem 10. Zeichen jedes 2.

Mit einer negativen Schrittweite kehrt man die Reihenfolge um

s = 'abcdefghijklmnopqrstuvwxyz'
s[::-1]                 # alles in umgekehrter Reihenfolge
s[::-2]                 # jedes 2. Zeichen in umgekehrter
                        # Reihenfolge

Unerwartete Ergebnisse kann man auch erhalten, wenn man einen negativen Stride mit Start und Endposition kombiniert

s = 'abcdefghijklmnopqrstuvwxyz'
s[0:10:-1]              # leeres Ergebnis
s[10:0:-1]              # vom 11. bis zum 2. Zeichen
                        # 'kjihgfedcb'

Diese Ergebnisse haben damit zu tun, wie Python intern die Schleife durchführt, um auf die entsprechenden Elemente zuzugreifen. Wenn man einen Teil einer Zeichenkette in inverser Reihenfolge braucht, ist es zumeist einfacher mit 2 Konstruktoren zu arbeiten und diese hintereinander zu stellen. Der erste wählt die Zeichen aus, der zweite dreht die Reihenfolge.

s[:10][::-1]            # die ersten 10 Zeichen in inverser Reihenfolge 'jihgfedcba'

5.3. Zeichenkettenfunktionen

Zeichenketten können mit diversen Funktionen und Methoden bearbeitet werden. Hier werde ich nur eine Auswahl darstellen.

Eine komplette Liste findet man hier: https://docs.python.org/3/library/stdtypes.html#string-methods

MethodeFunktion
len(s)Ermittelt die Anzahl der Zeichen
str(x)Wandelt x in eine Zeichenkette um
test in sTestet, ob test in s vorkommt
s.count(test)Ermittelt, wie oft test in s vorkommt
s.endswith(test)Testet, ob s mit test endet.
s.expandtabs()Ersetzt Tabukatorenzeichen durch Leerzeichen
s.find(test)Sucht test in s und liefert die Startposition oder -1 zurück
str.isxxxx(s)Testet die Eigenschaften von s: islower(), isdigit() usw.
s.join(x)Verbindet die Zeichenkette in x (Liste, Set, Tupel).
s.lower()Liefert die Zeichenkette in s in lauter Kleinbuchstaben zurück
s.partition(test)Trennt s auf und liefert drei Teile als Tupel zurück
s.replace(old, new)Liefert s zurück, wobei old durch new ersetzt wird
s.rfind(text)Wie find, beginnt aber am Ende der Zeichenkette
s.split(test)Zerlegt s bei jedem Vorkommen von test, liefert eine Liste
s.splitlines()Zerlegt s zeilenweise, liefert eine Liste.
s.startswith(test)Testet, ob s mit test beginnt.
s.strip()Entfernt Whitespaces vom Beginn und Ende.
s.upper()Wandelt die Zeichenkette s in Grossbuchstaben um.

Funtionen vs Methoden

Eigentlich sind Methoden so etwas ähnliches wie Funktionen, sie werden aber auf zugrundeliegenden Daten (Objekte) angewandt. Das äussert sich in der Schreibweise:   

function(daten)   
daten.methode()   
daten.methode(weitere, daten)


Somit die die Anwendung von Methoden also nicht zu schwierig. Da Python eine objektorientierte Programmiersprache ist, gibt es viel mehr Methoden als Funktionen. Hintergründe zu Objekten und Methoden wird im Kapitel 11 – Objektorientierte Programmierung behandelt.

# Beispiele zu Zeichenkettenfunktionen
s = 'abcdefghijklmnopqrstuvwxyz'

s.upper()           # liefert: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
'efg' in s          # liefert: True
s.count('efg')      # liefert 1
s.partition('e')    # liefert: ('abcd', 'e', 'fghijklmnopqrstuvwxyz')
s.split('e')        # liefert: ['abcd', 'fghijklmnopqrstuvwxyz']

5.3.1. Eigenschaften von Zeichen(-ketten) ermitteln

Es gibt verschiedene Funktionen um die Eigenschaften eines Zeichens oder einer Zeichenkette zu ermitteln.

FunktionErgebnis
len(‚abc‘)3
str.isalpha(‚a‘)True
str.isalpha(‚abcäöü‘)True
str.isalpha(‚abc123‘)False
str.isalpha(‚ ‚)False
str.isdigit(‚123‘)True
str.isalnum(‚abc123‘)True
str.isalnum(‚!‘)False
str.isascii(‚abc123r|$!‘)True
str.islower(‚abc‘)True
str.islower(‚abc123_‘)True
str.islower(‚abcD‘)False

5.3.2. Suchen und ersetzen

Mit find beginnt die Suche normalerweise am Beginn einer Zeichenkette. Mit optionalen Parametern kann der Startpunkt der Suche eingegrenzt werden.

s = 'abcdefghijklmnopqrstuvwxyz'
s.find('cde')           # 'cde' wird an Position 2 gefunden
s.find('efg', 4)        # auch wenn die Suche an dieser Position beginnt
                        # wird dieser gefunden
s.find('efg', 5)        # string wird nicht gefunden, da der Startpunkt
                        # nach dem ersten Zeichen beginnt

Solange nach einem String gesucht wird, der sich innerhalb der Zeichenkette befindet, so kann man auch die Methode index anwenden.Ist dieser String nicht vorhanden, so wirft Python einen Fehler -1 aus
replace ersetzt alle Vorkommnisse einer Suchzeichenkette durch eine andere Zeichenkette.

s = 'abcdefghijklmnopqrstuvwxyz'
s.replace('e', 'X')
# Ergebnis 'abcdXfghijklmnopqrstuvwxyz'

5.4. Zeichenketten formatieren und konvertieren

Sehr oft müssen aus Zahlen, Datums- und Zeitangaben Zeichenketten gebildet werden. Im einfachsten Fall verwendet man dazu deîe Funktion str(x) oder repr(x), die jedes Objekt als Zeichenketten darstellen können.

str bemüht sich die Zeichenkette so zu formatieren, dass diese für den Menschen gut lesbar ist.

repr gibt die präzise Darstellung mit Escape-Zeichen an, sodass die Ausgabe im Code nachgebildet werden kann.

from fractions import Fraction
x = Fraction('1/3')             # der Bruch 1/3 als Fraction -  Objekt
print(str(x))                   # Ausgabe: 1/3
s = repr(x)                     # maschinenlesbare Form
print(s)                        # Ausgabe: 'Fraction(1, 3)'
y = eval(s)                     # Rückumwandlung in ein Objekt
print(y)                        # Ausgabe: 1/3

5.4.1. Daten formatieren

Weder mit str noch mit repr haben Sie selbst Einfluss auf die Formatierung der resultierenden Zeichenketten.

Möchten Sie Zahlen rechtsbündig oder mit Tausendertrennungen darstellen möchten, so bietet dazu Python verschiedene Funktionen bzw. Verfahren an.

formatzeichenkette % (daten, daten, daten): Innerhalb der printf Funktion wird die formatzeichenkette in der Syntax formuliert. Innerhalb dieser Zeichenkette geben %-Zeichen die Position der einzusetzenden Daten an.

formatzeichenkette.format(daten, daten, daten): Diese Variante wird allen .Net Programmierern bekannt vorkommen. Innerhalb dieser Zeichenkette geben { } Klammernpaare die Position der Parameter an.
Seit der Python Version 3.6 kann dazu eine Kurzschreibweise benutzt werden, bei der der formatzeichenkette ein f vorangestellt wird. In den { } Klammerpaaren können Sie dann direkt den Namen der Python-Variablen verwenden.

locale.format_string(…): Diese Methode verwendet aus dem locale Modul die landesspezifische Einstellungen und verwendet z.B. in Deutschland ein Komma anstelle des Dezimalpunktes

5.4.2. Formatierung mit dem %-Operator

Als erstes einmal 3 Beispiele für das &-Verfahren.

print('%s ist %d Jahre alt.' % ('Mathias', 11))        # Mathias ist 11 Jahre alt.
print('1/7 mir drei Nachkommastellen: %.3f' % (1/7))   # 1/7 mit drei Nachkommastellen: 0.143
print('<img src="%s" alt="%s" width="%d">' % ('foto.jpg', 'Porträt', 200))
                                   # <img src="foto.jpg" alt="Porträt" width="200">

Die wichtigsten Codes zum Aufbau der Zeichenkette haben Ich Ihnen in der unten aufgeführten Tabelle dargestellt. Viele weitere finden Sie hier: https://docs.python.org/3/builtins/stdtypes.html#old-string-formatting-operations

CodeBedeutung
%dganze Zahl (dezimal)
%5dganze Zahl mit fünf Stellen, rechtsbündig
%-5dganze Zahl mit 5 Stellen, linksbündig
%fFliesskommazahl (float)
%.2fFliesskommazahl mit zwei Nachkommastellen
%rZeichenkette, Python verwendet repr
%sZeichenkette, Python verwendet s
%10sZeichenkette mit 10 Zeichen, rechtsbündig
%-10sZeichenkette mit 10 Zeichen, linksbündig
%xganze Zahl hexadezimal ausgeben

5.4.3. Formatierung mit der „format“ Methode

Der grösste Vorteil der neuen format-Methode besteht darin, dass die Platzhalterreiehenfolge durch {n} frei gewählt werden kann und daher unabhängig von der Reihenfolge der Programmierung und der Parameter ist. Eine vollständige Refernz finden Sie hier: https://docs.python.org/3/library/string.html#format-string-syntax

CodeBedeutung
{ {}Parameter, beliebiger Datentyp
{0}, {1}, …nummerierter Parameter
{eins}, {zwei}, …benannte Parameter
{:d}ganze Zahl
{:<7d}ganze Zahl mit 7 stellen, linksbündig
{:>7d}ganze Zahl mit 7 Stellen, rechtsbündig
{:^7d}ganze Zahl mit 7 Stellen, zentriert
{.f}Fliesskommazahl
{:,f}Fliesskommazahl mit Tausendertrennung
{:.5f}Fliesskommazahl mit fünf Nachkommastellen
{:n}Zahl mit Lokalisierung
{:s}Zeichenkette

Beachten Sie die eigenwillige Syntax in der Form fmtstr.format(daten, daten, daten)!

print('{} ist {} Jahre alt'.format('Sebastian', 13))   # Ausgabe: Sebastian ist 13 Jahre alt.

# umgekehrte Reihenfolge der Parameter!
print('{1} ist {0} Jahre alt'.format(13, 'Sebastian')) # Ausgabe: Sebastian ist 13 Jahre alt.

# benannte Parameter
print('{name} ist {alter} Jahre alt'.format(alter=13, name='Sebastian'))   
           # Ausgabe: Sebastian ist 13 Jahre alt.

print('1/7 mit drei Nachkommastellen: {.3f}', format(1/7))
           # Ausgabe: 1/7 mit drei Nachkommastellen: 0.143'

print('SELECT * FROM table WHERE id={:d}, format(324))  # Ausgabe: SELECT * FROM table WHERE id=324

5.4.4. format – Kurzschreibweise (ab Python 3.6)

Seit der Version Python 3.6 wurde noch eine weitere Variante hinzugefügt. Wenn Sie in der Formatierungszeichenkette Variablen verwenden und der Zeichenkette den Buchstaben f voransetzen, dann brauchen Sie weder format explizit aufrufen noch einen Parameter mit zu übergeben.

alter = 13
name = 'Sebastian'
print(f'{name} ist {alter} Jahre alt.')        # Augabe: Sebastian ist 13 Jahre alt.

Diese Schreibweise lässt sich auch mit den vorherigen zusammengefassten Formatierungsschreibweisen kombinieren.

x = 1/7
print(f'{x:.2}')      # x mit 2 Nachkommastellen ausgegeben: 0.14

Die Qual der Wahl

Welche Schreibweise Sie nun besser finden, entscheiden Sie selbst, Wenn Ihnen die printf Syntax eher liegt, so benutzen Sie diese. Liegt Ihnen mehr die Kurzschreibweise, so setzen Sie diese ein.
Alle 3 Möglichkeiten führen zum selben Ziel.

5.5. Lokalisierung

Im letzten Abschnitt haben wir über die Formatierungsverfahren gesprochen, mit % und mit format werden aber nicht die Spracheinstellungen des Systems berücksichtigt. Fliesskommazahlen werden immer mit dem US-typischen Dezimalpunkt ausgegeben.

x = 2.5
print("%f" % x)                 # Ausgabe: 2.500000
print('f{:f}'.format(x))        # Ausgabe: 2.500000

Um dieses Defaultverhalten ändern zu können, müssen Sie die Methode des locale-Moduls benutzen. Die darin erhaltenen Methoden helfen bei der Lokalisierung eines Programms, also bei der Anpassung an landestypische Anzeigen.

Zur formatierten Ausgebe verwenden Sie dann format_string(fmt, val) wobei die gleichen Syntaxregeln gelten wie für fmt % val.

import locale
# Einstellungen des Betriebssystems übernehmen
# (laut Python selbst - funktioniert aber öfters nicht)
locale.setlocale(locale.LC_ALL)

# Lokalisierung explizit für Linux einstellen
local.setlocale(locale.LC_ALL, 'de_DE.utf8')

# Lokalisierung explizit für macOS einstellen
local.setlocale(locale.LC_ALL, 'de_DE.UTF-8')

# Lokalisierung explizit für Windows einstellen
local.setlocale(locale.LC_ALL, 'german')

x = 2.5
print(locale.format_string('5f', x)             # Ausgabe in DE: 2,500000

print('{n}'.format(x))                          # Ausgabe: 2,5

5.5.1. Lokalisierte Zeichenketten in Zahlen umwandeln

Wenn Sie bei der Umwandlung von Zeichenketten in Zahlen die lokalisierung berücksichtigen möchten, so verwenden Sie die Methode atof.

s = '2,5'
x = locale.atof(s)
print(x*2)                                      # Ausgabe: 5

Lokalisierung von Zeitangaben

Die Methode des locale-Moduls sind auch erfolderlich, um Zeitangaben (z.B. Wochentage, Monatsnamen) landestypisch auszugeben. In Kapitel 6. Datum und Zeit werden wir uns mit diesem Thema beschäftigen.

5.5.2. Lokalisierungsbeispiel

Das nachfolgende Script erwartet die Eingabe von Länge und Breite eines Rechteckes, wobei das Deutsche Komma verwendet werden soll. Das Programm berechnet dann den Flächeninhalt und gibt den Wert mit 2 Nachkommastellen aus. Damit das Programm unter allen Betriebssystemen zufriedenstellend funktioniert, wird mit platform.system das Betriebssystem ermittelt und setlocale entsprechend ausgeführt.

import locale, platform
if platform.system() == 'Windows':
    locale.setlocale(locale.LC_ALL, 'german')
if platform.system() == 'Linux':
    locale.setlocale(locale.LC_ALL, 'de_DE.utf8')
else:
    locale.setlocale(locale.LC_ALL, 'de_DE.UTF8')

s = input('Länge des Rechtecks: ')                   # str
laenge = locale.atof(s)                              # float
s = input('Breite des Rechtecks: ')                  # str
breite = locale.atof(s)                              # float
flaeche = laenge + breite                            # float
s = locale.format_string('%.2f', flaeche)            # str
print('Flächeninhalt: ', s)

# Ausgabe:
# Länge des Rechtecks: 12,5
# Breite des Rechtecks: 7,8
# Flächeninhalt: 97,50

5.6. Reguläre Ausdrücke (Regular Expressions)

Wenn man links aus HTML Dokumenten extrahieren oder komplexe Suchen oder Ersetzen Vorgänge ausführen möchte, so kann man dieses mit regular expressions durchführen. In Python sind die entsprechenden Funktionen im Modul re gebündelt.

FunktionBedeutung
match(pattern, s)testet, ob s dem Muster pattern entspricht
search(pattern, s)Liefert die Position, an der das Muster vorkommt
split(pattern, s)zerlegt s bei jedem Vorkommen des Suchmusters
sub(pattern, r, s)Ersetzt das erste gefunden Muster in s durch r

Das folgende Beispiel überprüft eine eMail Adresse auf Ihre Gültigkeit.

import re
pattern = r'^[A-Za-z0-9\.\+_-]@[A-Za-z0-9\._-]+\.[a-zA-Z]+$'
email = input('Geben Sie eine gültige eMail Adresse ein: ')

if re.match(pattern, email):
  print('Die eMail Adresse ist gültig!')
else:
  print('Die eMail Adresse sieht Fehlerhaft aus.')

Man sieht an diesem Beispiel, dass das Zusammenstellen regulärer Ausdrücke sehr komplex sein kann. Für gängige Probleme findet man im Internet oft passende Lösungen.
Andernfalls muss man den regulären Ausdruck selber zusammenbasten, das Muster [a-z] bezieht sich auf eine aus Kleinbuchstaben zusammengesetzte Zeichenkette. Hier würde eine Zeichenkette die aus abc oder x oder xxx besteht gefunden werden, dagegen eine Zeichenkette a b würde nicht gefunden werden, da das Leerzeichen nicht abgefangen wird. 

CodeBedeutung
^Beginn der Zeichenkette
$Ende der Zeichenkette
.ein beliebiges Zeichen
[a-z]ein Kelinbuchstabe zwischen a und z
[a, b, f-h]ein Buchstabe aus a, b, f, g und h
[^0-9]ein beliebiges Zeichen ausser 0 bis 9
*Das Muster darf beliebig oft vorkommen (auch 0 mal)
+Das Muster darf beliebig oft vorkommen (mindestens aber einmal)
\xSpezialzeichen angeben (\$ steht als für ein $ Zeichen)

5.7. Aufgaben

1.) Wie bilden Sie eine Zeichenkette, die selbst ein Anführungszeichen enthält?

2.) Wie bilden Sie Zeichenketten, die das Zeichen \ enthalten?

3.) Extrahieren Sie aus der folgeden Zeichenkette das Tag zwischen den eckigen Klammern.

      bla [wichtig] mehr bla

4.) Zerlegen Sie den folgenden Dateinamen in Linux Notation in die Verzeichnisangabe (bis zum letzten /-Zeichen) und den eigentlichen Dateinamen

/home/dev/Bilder/foto1.jpg

5.) Fordern Sie einen Anwender dazu auf seinen Namen in einem Script einzugeben. Entfernen Sie danach alle Leerzeichen am Anfang und Ende der Eingabe

6.) Geben Sie drei maximal fünfstellige Zahlen rechtsbündig aus.

7.) Geben Sie ‚Hello, World!‘ in umgekehrter Reihenfolge aus.