# Strings

# Begrenzer ' und " bzw. ''' und """ für mehrzeilige Strings sind völlig
# gleichwertig
#
# Strings sind unveränderlich, String-Operationen erzeugen daher neue
# String-Objekte

# String-Verkettung mit + und *

print('a' + (' ' * 20) + 'b')
# die Klammern können entfallen (* bindet stärker als +)
print('a' + ' ' * 20 + 'b')

s = 'abc'
s += 'xyza' # s = s + 'xyza'
print(s)

# bei Literalen ist die Verkettung auch ohne + möglich
print('auto' 'bahn')

# bei mehreren Verkettungen und langen Strings empfehlen sich Listen und join()
s = []
s.append('abc')
s.append('xyza')
s = ''.join(s)
print(s)
print()

# String-Methoden
print(s.replace('a', 'X')) # XbcxyzX
print(s.zfill(20))         # 0000000000000abcxyza
print(s.ljust(20) + '|')   # abcxyza             |
print(s.rjust(20))         #              abcxyza
print(s.upper())           # ABCXYZA
print(s.upper().lower())   # abcxyza

print(s.startswith('a'))        # True
print(s.startswith(('a', 'c'))) # True
print(s.endswith('b'))          # False
print(s.endswith(('x', 'n')))   # False
print(s.find('ba'))             # -1
print()

# zeichenweise ausgeben: Iteration mittels for
for c in s: print(c)

# Slicing
print(s[0], s[-1], s[-2]) # a a z
print(s[2:5])             # cxy
print(s[:5])              # abcxy
print(s[3:])              # xyza
print(s[20:21])           # '' (s[20] erzeugt dagegen IndexError: string index out of range)

# Escape-Sequenzen: \n \r \t \\ \' \" ...
print('guten\ntag')
s = '  hallo allerseits\r\n'
print(repr(s))              # '  hallo allerseits\r\n'
print(repr(s.strip()))      # 'hallo allerseits'
print(repr(s.lstrip()))     # 'hallo allerseits\r\n'
print(repr(s.rstrip('\n'))) # '  hallo allerseits\r'

# reguläre Ausdrücke - Modul re
import re

# wir nutzen hier einen Raw-String (Backslash steht für sich selbst und leitet
# keine Escape-Sequenz ein);
# Muster \ba passt auf ein a am Wortanfang und a\b auf ein a am Wortende
mo = re.search(r'\ba|a\b', s)
if mo:
    # Muster gefunden: Position ausgeben
    print(mo.span()) # (8, 9)

# mit finditer() kann man die Treffer durchlaufen
print(list(re.finditer(r'\ba|a\b', 'b1b a2a c3c')))
# [<_sre.SRE_Match object; span=(4, 5), match='a'>, <_sre.SRE_Match object; span=(6, 7), match='a'>]

# den String mit den Index-Werten seiner Zeichen ausgeben
for i, c in enumerate(s): print(i, c)

# Musterersetzung
print(re.sub('a.*r', '', s))    # ab dem ersten a alles löschen
print(re.sub(r'\ba.*r', '', s)) # vom ersten a am Wortanfang bis zum letzten r alles löschen

# Strings in Listen aufspalten und Listen zu Strings zusammensetzen
print(s.split())
print(s.split('a'))

# join() verlangt Strings als Argumente
l = 'guten\ntag'.splitlines()
print(l)
print('|'.join(l))

# mit einem Generatorausdruck wandeln wir die Elemente von range(10) in Strings um
print('/'.join(str(n) for n in range(10)))

# Ausgabe in eine Datei
open('mylist', 'w').write('\n'.join(l))
    # anonmyes Dateiobjekt wird vom Garbage Collector geschlossen und beseitigt

with open('myfile.txt', 'w') as f:
    for line in l:
        print(l, file=f)

# ohne with:
# f = open('myfile.txt', 'w')
# ...
# f.close()

# Datei zeilenweise einlesen und Zeilen an die Liste anhängen
for line in open('mylist'):
    l.append(line)

print(l)

# Datei nochmal lesen und deren Zeilen an die Liste anhängen
l.extend(open('mylist'))

# mehrzeiliger String
mzs = '''
Python
ist
toll
'''
print(mzs)
print(mzs.strip())
