Ein String in Julia ist eine geordnete Folge von Zeichen. Wie das Handbuch anmerkt: „Der eigentliche Ärger beginnt natürlich dann, wenn man fragt, was ein Zeichen eigentlich ist."
Ein Großteil dieser Komplexität wird im Konzept Chars ausführlicher behandelt, aber kurz gesagt:
Im Allgemeinen werden Strings in doppelte Anführungszeichen " " eingeschlossen.
Einfache Anführungszeichen ' ' werden nur für Chars verwendet.
Es ist auch möglich, dreifache doppelte Anführungszeichen """ """ zu verwenden, wodurch " innerhalb des Strings ohne Escapezeichen genutzt werden kann.
Wichtiger noch: Bei mehrzeiligen Strings wird unerwünschte zusätzliche Einrückung entfernt.
julia> """
Multiline
"""
"Multiline\nString\n"
Wie die meisten Sprachen seit C verwendet Julia einen Backslash \ zum Escapen:
\n im vorherigen Beispiel.\$ (siehe unten).Im Prinzip lassen sich Strings genau wie Vektoren indizieren:
julia> s[1], s[5]
('J', 'a')
Für einen ASCII-String wie „Julia" funktioniert das offensichtlich, aber es ignoriert die meisten Sprachen der Welt.
Betrachte eines der Zeichen aus Beowulf, das vor etwa 15 Jahrhunderten im Altenglischen geschrieben wurde.
„Hrōðgār" besteht eindeutig aus 7 Zeichen, aber nicht alle davon sind ASCII.
julia> king = "Hrōðgār"
"Hrōðgār"
julia> length(king)
7
julia> isascii(king)
false
# collect() converts to a Char vector:
julia> collect(king)
7-element Vector{Char}:
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
'ō': Unicode U+014D (category Ll: Letter, lowercase)
'ð': Unicode U+00F0 (category Ll: Letter, lowercase)
'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)
'ā': Unicode U+0101 (category Ll: Letter, lowercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
Das Indizieren eines solchen Strings funktioniert zunächst, scheitert aber irgendwann:
julia> king[3]
'ō': Unicode U+014D (category Ll: Letter, lowercase)
julia> king[4]
ERROR: StringIndexError: invalid index [4], valid nearby indices [3]=>'ō', [5]=>'ð'
Das Problem ist, dass diese Art der Indizierung Bytes zählt, die bei Nicht-ASCII-Strings keine 1:1-Beziehung zu Zeichen haben.
Ein Unicode/UTF-8-Zeichen kann bis zu 4 Bytes zu seiner Darstellung benötigen, und das Konzept Chars wird dies weiter untersuchen.
Viele Sprachen verwenden + als String-Verkettungsoperator, aber Julia nicht.
Zumindest ist die Fehlermeldung hilfreich.
julia> "s1 " + "s2"
ERROR: MethodError: no method matching +(::String, ::String)
The function `+` exists, but no method is defined for this combination of argument types.
String concatenation is performed with *
julia> "s1 " * "s2"
"s1 s2"
Die Funktion string() verkettet eine beliebige Anzahl von Strings.
julia> string("lots ", "of ", "bits")
"lots of bits"
Die Funktion join() macht dasselbe und nimmt außerdem einen Vektor von Strings entgegen, den sie mit einem angegebenen Trennzeichen verkettet (standardmäßig "").
julia> join(["lots", "of", "bits"], "_")
"lots_of_bits"
Beachte, dass Strings unveränderlich sind und dass Verkettung Kopieren bedeutet. Wiederholte Verkettungen in einer Schleife sind daher ineffizient, und es ist besser, die Fragmente in einem Vektor zu sammeln und sie am Ende alle zusammenzufügen.
Einfach:
julia> repeat("Abc", 5)
"AbcAbcAbcAbcAbc"
Viele Sprachen haben eine Möglichkeit, berechnete Werte in Strings einzufügen, doch über die beste Syntax dafür herrscht außergewöhnliche Uneinigkeit.
In Julia steht vor interpolierten Werten ein $.
julia> myvar = 42
42
julia> "myvar evaluates to $myvar"
"myvar evaluates to 42"
julia> r = 5.3
5.3
julia> "A circle of radius $r has area $(π * r^2)"
"A circle of radius 5.3 has area 88.24733763933729"
Runde Klammern sind erforderlich, wenn ihr Weglassen mehrdeutig wäre, bei einem einzelnen Bezeichner, auf den Leerraum folgt, aber optional.
Um ein $ in den String aufzunehmen, escape es als \$.
Beachte die Einschränkung, dass die Interpolation derzeit keine Formatierung erlaubt, etwa die Anzahl der anzuzeigenden Nachkommastellen.
@sprintf()Für eine feinere Kontrolle über den Zusammenbau von Strings übernimmt Julia die Funktion sprintf aus C (und mehreren späteren Sprachen: Wikipedia listet etwa 30 auf).
In Julia ist dies als macro im Modul Printf implementiert, daher das Präfix @.
julia> using Printf
julia> r = 5.3
5.3
julia> @sprintf("A circle of radius %.1f has area %.2f", r, π * r^2)
"A circle of radius 5.3 has area 88.25"
Der Einfachheit halber konzentriert sich dieser Abschnitt auf Funktionen, die einen neuen String zurückgeben und die Eingabe unverändert lassen.
Viele haben ein Gegenstück, dessen Name das Suffix ! trägt und das die Eingabe direkt verändert.
Wie lang ist ein String? Manchmal hängt es davon ab, wie man zählt.
Der einfache Fall sind ASCII-Strings, bei denen jedes Zeichen 1 Byte belegt.
julia> string_asc = "Julia"
"Julia"
julia> length(string_asc)
5
julia> sizeof(string_asc)
5
Die Funktion length() gibt die Anzahl der Zeichen zurück, die Funktion sizeof() die Anzahl der Bytes.
Bei anderen Zeichensätzen wird dieser Unterschied wichtig:
julia> king = "Hrōðgār"
"Hrōðgār"
julia> length(king)
7
julia> sizeof(king)
10
Eine häufige Operation beim Programmieren besteht darin, einen langen String anhand eines Trennstrings aus einem oder mehreren Zeichen in Teile zu zerlegen.
Am allgemeinsten verwenden wir die Funktion split().
Das Trennzeichen ist standardmäßig (beliebiger) Leerraum, aber es können auch andere angegeben werden.
julia> split("my little string")
3-element Vector{SubString{String}}:
"my"
"little"
"string"
julia> split("My_snake_case_string", "_")
4-element Vector{SubString{String}}:
"My"
"snake"
"case"
"string"
Diese Beispiele zerlegen einen String in kleinere Strings. Das Zerlegen eines Strings in Zeichen ist eine andere Operation.
Enthält ein String einen bestimmten Teilstring?
Merkwürdigerweise gibt es zwei Funktionen, um das zu prüfen: occursin() und contains() unterscheiden sich nur in der Reihenfolge ihrer Argumente.
julia> needle = "Julia"
"Julia"
julia> haystack = "Python, Julia and R"
"Python, Julia and R"
julia> occursin(needle, haystack)
true
julia> contains(haystack, needle)
true
Genauer auf die Position bezogen:
julia> startswith(haystack, "Python")
true
julia> endswith(haystack, "Python")
false
Um die Start- und Endindizes eines Teilstrings zu erhalten, gibt es mehrere Funktionen:
findfirst()findlast()findprev()findnext()julia> findfirst(needle, haystack)
9:13
Um Teilstrings zu ersetzen, liste die Änderungen mit der Syntax x => y auf.
julia> replace("abc", "a"=>"b", "b"=>"c", "c"=>"a")
"bca"
Seit Julia 1.7 kann die Funktion replace eine beliebige Anzahl von Änderungen annehmen, wobei garantiert ist, dass kein Zeichen während des Ersetzens mehr als einmal geändert wird.
Die Syntax x => y heißt pair, ein wichtiger Typ in Julia, der im Konzept Dicts and Pairs genauer behandelt wird.
Oft müssen wir führenden und/oder abschließenden Leerraum aus einem String entfernen.
Dafür gibt es die Funktionen lstrip() (links), rstrip() (rechts) und strip() (beides).
julia> strip("\n\t useful_bit\n\n")
"useful_bit"
Diese Funktionen haben ziemlich selbsterklärende Namen:
julia> s = repeat("aBcD ", 5)
"aBcD aBcD aBcD aBcD aBcD "
julia> uppercase(s)
"ABCD ABCD ABCD ABCD ABCD "
julia> lowercase(s)
"abcd abcd abcd abcd abcd "
julia> titlecase(s) # Initial letter of each word uppercase
"Abcd Abcd Abcd Abcd Abcd "
In dieser Übung verarbeitest du Logzeilen.
Jede Logzeile ist ein String mit folgendem Format: "[<LEVEL>]: <MESSAGE>".
Es gibt drei verschiedene Log-Level:
INFOWARNINGERRORDu hast drei Aufgaben. Bei jeder bekommst du eine Logzeile und sollst etwas damit anfangen.
Implementiere die Funktion message, die die Nachricht einer Logzeile zurückgibt:
julia> message("[ERROR]: Invalid operation")
"Invalid operation"
Leerzeichen am Anfang und am Ende sollen entfernt werden:
julia> message("[WARNING]: Disk almost full\r\n")
"Disk almost full"
Implementiere die Funktion log_level, die das Log-Level einer Logzeile zurückgibt, und zwar in Kleinbuchstaben:
julia> log_level("[ERROR]: Invalid operation")
"error"
Implementiere die Funktion reformat, die die Logzeile umformatiert: Zuerst kommt die Nachricht, danach das Log-Level in runden Klammern:
julia> reformat("[INFO]: Operation completed")
"Operation completed (info)"
Hinweis: Alle Strings in dieser Übung sind auf Englisch und beschränken sich auf den ASCII-Zeichensatz. Später bekommst du in anderen Konzepten die Gelegenheit, mit Unicode-Zeichen zu arbeiten.
Melde dich bei Exercism an, um Julia mit 35 Konzepte128 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.