St

Stringek ebben a kurzusban: Julia

7 feladat

A(z) Stringek fogalomról

A String a Julia nyelvben karakterek rendezett sorozata. Ahogy a kézikönyv rámutat: „Persze az igazi baj akkor kezdődik, amikor valaki azt kérdezi, mi is az a karakter."

Ennek a bonyolultságnak a nagy részét részletesebben a Chars fogalom tárgyalja, de röviden:

  • A Julia minden stringje Unicode.
  • Azokkal a stringekkel, amelyek egyben ASCII karakterekből állnak (az angol ábécé nagy- és kisbetűi A-tól Z-ig, számjegyek és néhány írásjel), könnyű dolgozni.
  • A világ legtöbb más írásrendszerével lehetséges dolgozni, de több odafigyelést igényel.

Stringliterálok

Általában a stringeket idézőjelek közé zárjuk: " ". Az egyszeres idézőjelet ' ' csak Chars esetén használjuk.

Három idézőjelet """ """ is használhatunk, így a stringen belül " is szerepelhet escape-elés nélkül. Ennél is fontosabb, hogy a többsoros stringekről a felesleges behúzást eltávolítja.

julia> """
       Multiline
       String
       """
"Multiline\nString\n"

Karakterek escape-elése

A C-től kezdődő nyelvek többségéhez hasonlóan a Julia is visszaperjelet \ használ az escape-eléshez:

  1. Nem nyomtatható karakterek bevitelére, például az előző példában szereplő sortörés \n beírására.
  2. Olyan karakterek védelmére, amelyek egyébként különleges jelentéssel bírnának, például a \$ (lásd alább).

Iteráció

A string egy bejárható gyűjtemény, ezért a for ... in ciklus anélkül működik, hogy karakterek vektorává kellene alakítani.

julia> s = "Julia"
"Julia"

# admittedly, this is a silly example
julia> for c in s; print(c, "; "); end
J; u; l; i; a; 

Az ilyen iterálásnak az az előnye, hogy a Julia a nem ASCII stringek esetében is helyesen kezeli a karakterhatárokat. Mindennek a jelentősége a következő szakaszban válik világosabbá.

Indexelés

Elvileg a stringek pontosan úgy indexelhetők, mint a vektorok:

julia> s[1], s[5]
('J', 'a')

Ez nyilvánvalóan működik egy olyan ASCII string esetén, mint a „Julia", de figyelmen kívül hagyja a világ nyelveinek nagy részét.

Vegyük a Beowulf egyik karakterét, amelyet mintegy 15 évszázaddal ezelőtt óangolul írtak.

A „Hrōðgār" nyilvánvalóan 7 karakterből áll, de nem mindegyikük 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)

Egy ilyen string indexelése jól indul, de egy ponton elakad:

julia> king[3]
'ō': Unicode U+014D (category Ll: Letter, lowercase)

julia> king[4]
ERROR: StringIndexError: invalid index [4], valid nearby indices [3]=>'ō', [5]=>'ð'

A probléma az, hogy az ilyen indexelés bájtokat számol, amelyek a nem ASCII stringek esetében nincsenek 1:1 kapcsolatban a karakterekkel. Egy Unicode/UTF-8 karakter akár 4 bájtot is igénybe vehet, és a Chars fogalom ezt részletesebben is kifejti.

Stringek építése

Összefűzés

Sok nyelv a + operátort használja stringek összefűzésére, de a Julia nem. Legalább a hibaüzenet segítőkész.

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"

A string() függvény tetszőleges számú stringet fűz össze.

julia> string("lots ", "of ", "bits")
"lots of bits"

A join() függvény ugyanezt teszi, és stringek vektorát is összefűzi egy megadott elválasztóval (amely alapértelmezésben "").

julia> join(["lots", "of", "bits"], "_")
"lots_of_bits"

Vegyük észre, hogy a stringek megváltoztathatatlanok, és az összefűzés másolással jár. Ezért a cikluson belüli ismételt összefűzés nem hatékony, jobb, ha a darabokat egy vektorban gyűjtjük össze, és a végén fűzzük össze az egészet.

Ismétlés

Egyszerű:

julia> repeat("Abc", 5)
"AbcAbcAbcAbcAbc"

Interpoláció

Sok nyelvben van mód arra, hogy kiszámított értékeket illesszünk stringekbe, bár abban meglepően nagy az egyet nem értés, hogy melyik a legjobb szintaxis.

A Juliában az interpolált értékeket $ előzi meg.

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"

A zárójelek kötelezőek, ha elhagyásuk kétértelmű lenne, de egyetlen, szóközzel követett azonosító esetén elhagyhatók.

Ha a stringben $ szerepel, escape-eld \$ formában.

Jegyezzük meg a korlátot: az interpoláció jelenleg nem tesz lehetővé formázást, például a megjelenítendő tizedesjegyek számát.

Megoldások:

  • A számítást csomagold egy round() függvénybe.
  • Az Exercism tesztfuttatóján kívül a PyFormattedStrings csomag a Python f-stringjeit utánozza.
  • A @sprintf() makrót alább ismertetjük.

@sprintf()

A stringek összeállítása feletti finomabb vezérléshez a Julia a C-ből (és számos későbbi nyelvből: a Wikipédia mintegy 30-at sorol fel) másolja a sprintf függvényt.

A Juliában ezt a Printf modulon belüli macro valósítja meg, innen a @ előtag.

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"

Stringfüggvények

Az egyszerűség kedvéért ez a szakasz azokra a függvényekre összpontosít, amelyek új stringet adnak vissza, és a bemenetet változatlanul hagyják. Soknak van egy ! utótaggal jelölt megfelelője, amely helyben módosítja a bemenetet.

Hossz

Milyen hosszú egy string? Néha attól függ, hogyan számolsz.

Az egyszerű eset az ASCII string, ahol minden karakter 1 bájtot foglal el.

julia> string_asc = "Julia"
"Julia"

julia> length(string_asc)
5

julia> sizeof(string_asc)
5

A length() függvény a karakterek számát adja vissza, a sizeof() pedig a bájtokét.

Ez a különbség más karakterkészleteknél válik fontossá:

julia> king = "Hrōðgār"
"Hrōðgār"

julia> length(king)
7

julia> sizeof(king)
10

Felosztás

A programozásban gyakori művelet egy hosszú stringet darabokra bontani egy vagy több karakterből álló elválasztó string alapján.

A legáltalánosabb esetben a split() függvényt használjuk. Az elválasztó alapértelmezésben bármilyen whitespace, de más is megadható.

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"

Ezek a példák egy stringet kisebb stringekre bontanak. Egy string karakterekre bontása más művelet.

julia> collect("input string")
12-element Vector{Char}:
 'i': ASCII/Unicode U+0069 (category Ll: Letter, lowercase)
 'n': ASCII/Unicode U+006E (category Ll: Letter, lowercase)
 'p': ASCII/Unicode U+0070 (category Ll: Letter, lowercase)
 'u': ASCII/Unicode U+0075 (category Ll: Letter, lowercase)
 't': ASCII/Unicode U+0074 (category Ll: Letter, lowercase)
 ' ': ASCII/Unicode U+0020 (category Zs: Separator, space)
 's': ASCII/Unicode U+0073 (category Ll: Letter, lowercase)
 't': ASCII/Unicode U+0074 (category Ll: Letter, lowercase)
 'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
 'i': ASCII/Unicode U+0069 (category Ll: Letter, lowercase)
 'n': ASCII/Unicode U+006E (category Ll: Letter, lowercase)
 'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)

Keresés és csere

Tartalmaz-e egy string egy megadott részstringet? Furcsamód két függvény is teszteli ezt: az occursin() és a contains() csak az argumentumaik sorrendjében térnek el.

julia> needle = "Julia"
"Julia"

julia> haystack = "Python, Julia and R"
"Python, Julia and R"

julia> occursin(needle, haystack)
true

julia> contains(haystack, needle)
true

A pozíció pontosabb meghatározásához:

julia> startswith(haystack, "Python")
true

julia> endswith(haystack, "Python")
false

Egy részstring kezdő:záró indexeinek megkereséséhez több függvényünk is van:

julia> findfirst(needle, haystack)
9:13

Részstringek cseréjéhez sorold fel a változtatásokat x => y szintaxissal.

julia> replace("abc", "a"=>"b", "b"=>"c", "c"=>"a")
"bca"

A Julia 1.7 óta a replace függvény tetszőleges számú változtatást fogadhat, azzal a garanciával, hogy a csere során egyetlen karakter sem változik meg egynél többször.

Az x => y szintaxist pair-nek nevezzük; ez egy fontos típus a Juliában, amelyről részletesebben a Dicts and Pairs fogalom szól.

Megjegyzés: Az egyszerűség kedvéért a fenti példák mind string literálokat használnak. A függvények közül sok általánosabb, és reguláris kifejezésekkel is működik. Erre egy későbbi fogalomban térünk vissza.

Whitespace

Gyakran kell egy string elejéről és/vagy végéről whitespace-t eltávolítanunk.

Erre valók az lstrip() (bal), rstrip() (jobb) és strip() (mindkettő) függvények.

julia> strip("\n\t  useful_bit\n\n")
"useful_bit"

Kis- és nagybetűváltás

Ezeknek a függvényeknek meglehetősen beszédes a nevük:

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 "

Parszolás

Gyakran hasznos a számok és stringreprezentációjuk közötti átalakítás.

A számból stringgé alakítás egyszerű, bár az alapértelmezett 10-től eltérő számrendszerhez egy plusz paraméter kell:

julia> string(42)
"42"

julia> string(42, base=16)
"2a"

julia> string(42, base=2)
"101010"

Egy string parszolása számérték előállításához kicsit bonyolultabb, és több hibalehetőséget rejt magában. A cél numerikus típus megadása kötelező. A számrendszer megadása opcionális, alapértelmezésben 10.

julia> parse(Int, "42")
42

julia> parse(Float64, "42")
42.0

julia> parse(Int, "42?")
ERROR: ArgumentError: invalid base 10 digit '?' in "42?"

julia> parse(Int, "42 ")  # whitespace may be tolerated
42

Különleges stringek

Néha hasznos, ha elnyomjuk a szokásos interpolációt és escape-elést a stringeken belül. Ehhez írd a nyitó idézőjel elé a raw szót.

julia> x = 10
10

julia> "x = $x if we use \$ for interpolation"
"x = 10 if we use \$ for interpolation"

julia> raw"x = $x if we use \$ for interpolation"
"x = \$x if we use \\\$ for interpolation"

A reguláris kifejezéseknek saját bonyolult szintaxisuk van, és a Julia két hasznos stringtípust kínál: a r" " a regexhez és az s" " a rögzített részekkel való munkához.

Számos más különleges string ritkábban fordul elő az Exercism-stílusú programozásban, bár könyvtárak készítésekor széles körben használják.

  • A szemantikus verzió stringek v"x.y.z" a szoftverkiadások főverzió.alverzió.javítás számozását kezelik.
  • A bájttömb-literálok b" " megkerülik a Unicode karakterhatárokat, és bájt szinten működnek.
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Stringek fogalmat

A gyakorlás zárolva

Oldj fel még 2 feladatot, hogy gyakorolhasd a(z) Stringek fogalmat