Escape-Sequenzen in Python-Strings          (C) 2016-2024 T.Birnthaler OSTC GmbH
==================================

Doku --> docs.python.org/3/reference/lexical_analysis.html#literals
         docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals

Das Zeichen "\" (Backslash) dient in Python innerhalb von Strings als
Escape-Zeichen ("Fluchtzeichen"), das zusammen mit dem DIREKT FOLGENDEN Zeichen
eine spezielle Bedeutung hat. Darüber werden z.B. Steuerzeichen (Strg-Z) und
Unicode-Zeichen über ihren ZEICHEN-CODE/CODE-POINT oder NAMEN angesprochen oder
ein Sonderzeichen " ' \ wird dadurch zu einem normalen Zeichen  \" \' \\.

Folgende Escape-Sequenzen (ES) sind in Python definiert:

  +--------------------+-----------------------------------------------------+
  | ES  Oct   Hex  Dez | Bedeutung                                           |
  +--------------------+-----------------------------------------------------+
  | \\  \134  \x5C  92 | Backslash (doppelt!)                    [backslash] |
  | \'  \047  \x27  39 | Hochkomma (in '...' notwendig)       [single quote] |
  | \"  \042  \x22  34 | Gänsefüßchen (in "..." notwendig)    [double quote] |
  +--------------------+-----------------------------------------------------+
  | \a  \007  \x07   7 | Klingel (BEL)                          [alert,bell] |
  | \b  \010  \x08   8 | Rückschritt (BS)                        [backspace] |
  | \t  \011  \x09   9 | Horizontaler Tabulator (HT)  [horizontal tabulator] |
  | \n  \012  \x0A  10 | Zeilenumbruch (LF)               [newline,linefeed] |
  | \v  \013  \x0B  11 | Vertikaler Tabulator (VT)      [vertical tabulator] |
  | \f  \014  \x0C  12 | Seitenvorschub (FF)                     [form feed] |
  | \r  \015  \x0D  13 | Wagenrücklauf (CR)                [carriage return] |
  +--------------------+-----------------------------------------------------+
  | \0  \000  \x00   0 | Null-Byte (NUL)                              [null] |
  |     \033  \x1B  27 | Escape (ESC)                               [escape] | \e geht nicht!
  |     \177  \x7F 127 | Delete (DEL)                               [delete] |
  +--------------------+-----------------------------------------------------+
  | \OOO               | Z. mit Oktalcode "OOO" (000-377)            [octal] |
  | \xHH               | Z. mit Hexadezimalcode "HH" (00-ff)   [hexadezimal] |
  | \uXXXX             | Z. mit 16-Bit Unicode-Wert "XXXX"         [unicode] |
  | \UXXXXXXXX         | Z. mit 32-Bit Unicode-Wert "XXXXXXXX"     [Unicode] |
  | \N{NAME}           | Z. mit Unicode-Name "NAME"                   [Name] |
  +--------------------+-----------------------------------------------------+
  | \<NEWLINE>         | Zeilenende wird ignoriert       [line continuation] |
  | \<SONST>           | Bleibt stehen inkl. Backslash              [FEHLER] |
  +--------------------+-----------------------------------------------------+

HINWEISE:

* Innerhalb von RAW-STRINGS r"..." oder R"..." werden Escape-Sequenzen
  nicht interpretiert, d.h. Backslash "\" zählt dort als normales Zeichen.

* Ein Backslash "\" direkt vor dem Zeilenende ("Line Continuation") verknüpft
  die aktuelle Zeile mit der folgenden zu einer LOGISCHEN ZEILE und erlaubt die
  Zerlegung von langen Zeilen in kurze Stücke. Die Einrückung der Folgezeile ist
  dabei irrelevant und muss nicht den Einrückungsregeln von Python gehorchen.

    erg = 1 + 2 + 3

  Entspricht: erg = 1 + 2 + 3

* Zeichenketten werden in Python durch folgende Syntax definiert (quotiert):

  +-----------------+-----+-------------------------------------------------+
  | Syntax          |     | Bedeutung                                       |
  +-----------------+-----+-------------------------------------------------+
  | "..."           | E 1 | Alle Zeichen (außer " und Zeilenvorschub)       |
  | '...'           | E 1 | Alle Zeichen (außer ' und Zeilenvorschub)       |
  | """..."""       | E m | Alle Zeichen (inklusive " ' und Zeilenvorschub) |
  | '''...'''       | E m | Alle Zeichen (inklusive " ' und Zeilenvorschub) |
  +-----------------+-----+-------------------------------------------------+
  | b"..."  B"..."  | E 1 | Binär-String (PY2-Standard)                     |
  | f"..."  F"..."  | E 1 | Format-String mit Platzhaltern der Form {...}   |
  | r"..."  R"..."  | - 1 | Raw-String (Escape-Sequenz nicht interpretiert) |
  | u"..."  U"..."  | E 1 | Unicode-String (PY3-Standard)                   |
  +-----------------+-----+-------------------------------------------------+
  | ur"..." UR"..." | - 1 | Raw-String im Unicode-Format                    |
  | ru"..." RU"..." | - 1 | Raw-String im Unicode-Format                    |
  | fr"..." FR"..." | - 1 | Raw-Format-String                               |
  | rf"..." RF"..." | - 1 | Raw-Format-String                               |
  | br"..." BR"..." | - 1 | Raw-Binär-String                                |
  | rb"..." RB"..." | - 1 | Raw-Binär-String                                |
  +-----------------+-----+-------------------------------------------------+
    E = Escape-Sequenz \X wird interpretiert (1 Zeichen)
    - = Escape-Sequenz \X bleibt erhalten (2 Zeichen)
    1 = Nur einzeiliger String möglich
    m = Mehrzeiliger String sowie ' und " im String erlaubt

HINWEIS:

* String-Literale, die DIREKT aufeinander folgen, werden automatisch verkettet
  (das Verkettungszeichen "+" dazwischen ist nicht notwendig):

    "hallo" "welt" 'usw.'            # --> 'halloweltusw.'
    "hallo" + "welt" + 'usw.'        # --> 'halloweltusw.'
    "hallo" ' ' "welt" ' ' "usw."    # --> 'hallo welt usw.'

  Gilt auch dann, wenn die String-Literale auf mehrere Zeilen verteilt sind:

    "hallo"                          # --> "halloweltusw."
    "welt"                           #
    "usw."                           #

  Funktioniert allerdings NICHT mit Variablen, Funktionen, Konstanten, ... (TODO):

    text                             # text = "hallo"
    "WELT".lower()                   # Funktion auf String "WELT" anwenden
    string.ascii_lowercase           # Konstante

BEISPIELE:

  print("Hallll\b\bo\t\\Welt")       # 'Hallo    \Welt'
  print('Hallll\b\bo\t\\Welt')       # 'Hallo    \Welt'
  print('''Hallll\b\bo\t\\Welt''')   # 'Hallo    \Welt'
  print("""Hallll\b\bo\t\\Welt""")   # 'Hallo    \Welt'
  print(r"Hallll\b\bo\t\\Welt")      # 'Hallll\b\bo\t\\Welt' (Raw-String)
  print(R"Hallll\b\bo\t\\Welt")      # 'Hallll\b\bo\t\\Welt' (Raw-String)
  print("Hallo \                     # Zeilenfortsetzung im String
         Welt")                      # (\n unterdrückt, Präfix 2. Zeile dabei)
  print("Hallo " + \                 # Zeilenfortsetzung im Code
        "Welt")                      # (\n und Präfix 2. Zeile unterdrückt)
  print("Hallo " "Welt")             # 'Hallo Welt' (automatische Verkettung)
  print("Hallo " + "Welt")           # 'Hallo Welt' (explizite Verkettung)

Unicode-Zeichen per Code und per Name ansprechen:

  print(
      "\x41 \101 \u0041 \U00000041 \N{LATIN CAPITAL LETTER A}",         # A A A A A
      "\x61 \141 \u0061 \U00000061 \N{LATIN SMALL LETTER A}",           # a a a a a
      "\x5A \132 \u005A \U0000005A \N{LATIN CAPITAL LETTER Z}",         # Z Z Z Z Z
      "\x7A \172 \u007A \U0000007A \N{LATIN SMALL LETTER Z}",           # z z z z z
      "\u03A0 \U000003A0 \N{GREEK CAPITAL LETTER PI}",                  # Π Π Π
      "\u03C0 \U000003C0 \N{GREEK SMALL LETTER PI}",                    # π π π
      "\u00E4 \U000000E4 \N{LATIN SMALL LETTER A WITH DIAERESIS}",      # ä ä ä
      "\u00F6 \U000000F6 \N{LATIN SMALL LETTER O WITH DIAERESIS}",      # ö ö ö
      "\u00FC \U000000FC \N{LATIN SMALL LETTER U WITH DIAERESIS}",      # ü ü ü
      "\u00DF \U000000DF \N{LATIN SMALL LETTER SHARP S}",               # ß ß ß
      "\u00C4 \U000000C4 \N{LATIN CAPITAL LETTER A WITH DIAERESIS}",    # Ä Ä Ä
      "\u00D6 \U000000D6 \N{LATIN CAPITAL LETTER O WITH DIAERESIS}",    # Ö Ö Ö
      "\u00DC \U000000DC \N{LATIN CAPITAL LETTER U WITH DIAERESIS}",    # Ü Ü Ü
      "\u00D7 \U000000D7 \N{MULTIPLICATION SIGN}",                      # × × ×
      "\u4e14 \U00004e14 \N{CJK UNIFIED IDEOGRAPH-4E14}",               #
      sep="\n",
  )

HINWEIS: Bei Thonny gibt es leider Schwierigkeiten mit Unicode-Zeichen
         ab "\U0010000", diese führen zum "Einfrieren" der GUI.

      "\u4e14 \U00004e14 \N{CJK UNIFIED IDEOGRAPH-4E14}",               # 且 且 且
      "\U0001f970 \N{SMILING FACE WITH SMILING EYES AND THREE HEARTS}", # 🥰 🥰 🥰

Konvertierungs-Funktionen zwischen Zeichen und Zeichen-Code/Code-Point:

  print(                          #
    hex(ord('π')),                # '03c0' (hexadecimal, ordinal)
    hex(ord('\u03C0')),           # '03c0'
    ord('π'),                     # 960
    ord('\u03C0'),                # 960
    chr(0x03C0),                  # 'π'    (character)
    chr(960),                     # 'π'
    chr(int('03C0', 16)),         # 'π'
    chr(int('0x03C0', 0)),        # 'π'
    sep="\n",                     #
  )                               #

  import unicodedata              # Modul importieren
  print(                          #
    unicodedata.name('\u03A0'),   # 'GREEK CAPITAL LETTER PI'
    unicodedata.name('\u03C0'),   # 'GREEK SMALL LETTER PI'
    sep="\n",                     #
  )                               #