Seriál Ruby on Rails 7: Datové typy: String
Práce s řetězci v Ruby. Vysvětlení některých základních operací s řetězci.
Předchozí dva datové typy byly poměrně jednoduché, operace s nimi jsou vcelku intuitivní, a ve velké míře matematicky logické. První složitější datový typ, se kterým jsme se opět již setkali v některých ukázkových příkladech, je String.
Typ String poznáme v kódu, nebo zapisujeme, vymezen do jednoduchých apostrofů nebo uvozovek. V obou případech vzniká nová instance třídy String, rozdíl je v chování interpretu a zpracování výsledného řetězce.
1 2 |
puts 'ahoj svete'.class #vypise String puts "ahoj svete".class #vyipse String |
I když se na první pohled jeví oba řádky identické, z pohledu interpretu a zpracování hodnot jsou úplně rozdílně, rozdíl způsobí právě uvozovací znaky, které použijeme.
Jednodušší je psaní textu do apostrofů. Slovem jednodušší se myslí z pohledu zpracování. Interpret v takovém případě řetězec vezme přesně tak jak je a tak jej zpracuje. Nekontroluje jeho obsah a nezdržuje se jeho podrobným zpracováním, na rozdíl od textu uvedeného v uvozovkách.
Uvozovky dodávají práci s řetězci nový rozměr. Text uvozený v uvozovkách bude interpretem podrobně rozebrán a upraven přesně podle jeho syntaxe, toto zpracování je samozřejmě složitější a programátor se musí sám rozhodnout, kterou z možností využije a kterou právě potřebuje.
Zpětné lomítko
První zajímavou věcí v řetězci uvedeném v uvozovkách je zpětné lomítko. Zpětné lomítko nám umožňuje vytvářet jednoduché konvence, které interpret Ruby zpracovává a vyhodnocuje. Podívejte se na tabulku povolených konvencí:
t | znak tabulátoru |
n | znak konce řádku |
r | odentrování na nový řádek, oproti n odřádkuje i když řetězec nepokračuje |
t | znak tabulátoru |
s | znak prázdné mezery |
\ | znak zpětného lomítka |
” | znak uvozovky |
V Ruby existuje takových notací mnohem více, ovšem pro naše účely nám prozatím budě těchto několik stačit.
Můžeme si je vyzkoušet na příkladu:
1 2 |
puts "ahojntsveter" puts "text ktery obsahuje "uvozovky"" |
Oba příklady budou parterem zpracovány a vyhodnoceny a až poté vráceny na výstup.
Zajímavá je poslední notace, která nám umožňuje psát uvozovku ve Stringu uvozeném v uvozovkách. Tuto nutnost můžeme simulovat textem psaným v apostrofech:
1 |
puts 'text ktery obsahuje "uvozovky"' |
Zpracování výrazů v řetězci
Krom jednoduchých notací pomocí zpětného lomítka můžeme přímo v řetězci zpracovávat i složitější struktury. Toto zpracování opět vyvoláme speciální konvencí, která má tvar #{}. Všechny výrazy uvedeny mezi složenými závorkami jsou poté zpracovány a vyhodnoceny. Do řetězce je vytištěn pouze výsledek tohoto výrazu:
1 2 |
puts "Nula ma nulovou hodnotu: #{0.zero?}" puts "4 + 5 = #{4 + 5}" |
Při psaní výrazů se nemusíme nijak omezovat a můžeme vyhodnocovat i proměnné obsahující hodnotu. Pokud je výraz platný, interpret jej dokáže zpracovat:
1 2 3 |
delenec = 20 delitel = 5 puts "vysledek vyrazu: #{delenec}/#{delitel} = #{delenec/delitel}" |
Uvědomte si ovšem, že každý příklad je možné simulovat pomocí apostrofů, kde výrazy sice vyhodnocovány nejsou, ale zato jsou zpracovány rychleji (interpret je nemusí parsovat).
1 2 3 |
jmeno = 'Jiri' prijmeni = 'Zachar' puts 'Moje jmeno je: '+ jmeno + ' ' + prijmeni |
Velikost znaků v řetězci – capitalize, downcase, upcase, swapcase
Pro práci s řetězci nám Ruby nabízí opravdu bohatou zásobu nejrůznějších funkcí. Jaké první se podívejme na skupinu 4 funkcí, které dokáží upravit velikosti jednotlivých znaků v řetězci. Tyto funkce mají společné to, že na rozdíl od jiných funkcí, zachovávají význam a sturkturu řetězce, pouze v něm mění velikosti písmen:
- capitalize – převede první znak na velký, ostatní znaky převede na malé
- downcase – převede všechny znaky na malé
- upcase – převede všechny znaky na velké
- swapcase – prohodí velikosti písmen, malá písmena převede na velká a naopak.
1 2 3 4 5 |
retezec = "programovani v RUBY je fajn. 123" puts retezec.capitalize #prevede první znak na velky puts retezec.downcase #prevede vsechny znaky na mala pismena puts retezec.upcase #prevede vsechny znaky na velka pismena puts retezec.swapcase #prohodi velikosti pismen v retezci |
Length
Funkce nám umožňuje zjistit délku řetězce. Tuto délku vrací jako typ FixNum, případně BigNum. Hodnota se počítá včetně bílých znaků na konci a na začátku řetězce.
1 2 3 4 |
retezec = "ahoj svete" delka = retezec.length #zjisteni delky puts delka #vypise 10 puts delka.class #datovy typ je FixNum |
Funkce správně vyhodnotí i délku řetězce, který obsahuje speciální notace. Tyto notace jsou nejdříve vyhodnoceny, a až poté je zjištěna délka výsledného řetězce. Můžete si vyzkoušet následující příklad:
1 2 |
puts ""sssss"".length #vypise 7 puts "#{4+5}".length #vypise 1 |
Obsah řetězce – include?, index, empty?
Dost často se setkáte s problémem, kdy budete potřebovat zjistit o řetězci nějaké informace. Ruby nám nabízí již připravené řešení v podobě několika základních funkcí, pomocí kterých můžete svůj problém řešit, nebo na nich minimálně své řešení postavit:
- include? – zjistí, zda řetězec obsahuje znak, nebo jiný řetězec
- index – zjistí, na jaké pozici řetězec obsahuje daný znak, nebo jiný řetězec.
- empty? – zjistí, zda je řetězec prázdný.
Ruby samozřejmě nabízí více podobně zaměřených funkcí, prozatím si ale vystačíme s tímto základem. Jednotlivé funkce si můžeme ukázat na příkladech.
Funkce include? vrací pouze hodnoty pravda nebo nepravda (true, false):
1 2 3 |
s = "ahoj svete" puts s.include?("ahoj") #vrací true puts s.include?('1') #vraci false |
Index pracuje víceméně podobně, pouze s tím rozdílem, že návratová hodnota je číselný typ FixNum, který obsahuje pozici hledaného řetězce. V případě že řetězec nebyl nalezen, vrací hodnotu nil:
1 2 3 4 |
s = "ahoj svete" puts s.index("ahoj") #vrací 0 puts s.index('x') #vraci nil puts s.index("s") #vraci 4 - najde znak mezery |
Poslední funkce kterou máme v této skupině uvedenou, funkce empty? opět vrací pouze hodnotu true nebo false, kdy se kontroluje, zda je řetězec prázdný:
1 2 |
puts "".empty? #vraci true puts " ".empty? #vraci false |
Úprava řetězce – squeeze, strip, reverse, insert, slice, delete
Další skupina funkcí, na které se podíváme nám umožňuje již přímo řetězec upravovat, a měnit jeho tvar a strukturu.
V řetězci můžeme nahrazovat znaky, můžeme v něm měnit pořadí znaků a podobně:
- squeeze – nahradí po sobě jdoucí stejné znaky pouze jedním znakem
- strip – odstraní z řetězce prázdné znaky na začátku a na konci
- reverse – vrací řetězec s obráceným pořadím znaků
- insert – vkládá na určitou pozici řetězce jiný řetězec
- slice – ořeže řetězec na určitou velikost
- delete – smaže z řetězce jeho část
Jak je vidět, funkcí pro úpravu řetězců je opravdu dost a možnosti, jak se řetězcem manipulovat je celá řada.
Squeeze funguje tak, že nahrazuje po sobě jdoucí stejné znaky pouze jedním z těchto znaků. Dokáže tak například promazat přebytečné mezery v textu.
Funkci můžeme volat několika způsoby:
- bez parametrů funkce vymaže všechny po sobě jdoucí znaky. Projde celý řetězec a pokud jsou v něm dva po sobě jdoucí znaky stejné, nechá pouze jeden z nich.
- pokud jako parametr uvedeme znak, funkce právě tento znak bude v řetězci nahrazovat
- navíc můžeme uvést výčet znaků, které funkce akceptovat a se kterými bude pracovat
1 2 3 4 |
puts "1122334455".squeeze #vraci 12345 puts "1122334455".squeeze("1") #vraci 122334455 puts "1122334455".squeeze("1234") #vraci 123455 puts "aabbccddeeff".squeeze("a-d") #vraci abcdeeff |
Funkci strip bychom mohli brát jako takovou jednodušší alternativu k squeeze, kdy tato funkce dokáže nahradit bílé znaky na začátku a na konci řetězce. Funkce nemá žádný parametr, který by do něj vstupoval, ale automaticky bere v potaz všechny bílé znaky:
1 2 |
puts " ahoj svete ".strip #vraci ahoj svete puts "nns ahoj svete nr".strip #vraci ahoj svete |
Reverse vrací nový řetězec, který má změněné pořadí všech znaků v řetězci. Tato funkce jednoduše vezme celý řetězec a bez jediné změny jej převrátí:
1 2 |
puts "ahoj svete".reverse #vraci etevs joha puts "cislo: #{4 + 5}" .reverse #vraci 9 :olsic |
Funkce insert je co se týká použití vcelku jednoduchá, nemusíte v ní hledat žádnou složitost. Obsahuje dva vstupní parametry, z nichž první je číslo značící pozici znaku v řetězci a druhý je právě řetězec, který na danou pozici umístí: Pozice 0 je potom začátek řetězce.
Pozici můžeme zadat navíc jako zápornou hodnotu, v takovém případě se počítá od konce:
1 2 3 |
#v obou pripadech vraci ahoj svete puts "ahoj".insert(4, " svete") puts "svete".insert(-6, "ahoj ") |
Pro ořez řetězce máme u funkce slice několik možností pro zadání podmínky ořezání. Prozatím si ukážeme pouze dvě možnosti, časem se dostaneme i k dalším (pomocí regulárních výrazů).
- zadání rozmezí dvou čísel FixNum, kde první určuje počátek a druhé počet znaků, které v řetězci po ořezání zůstanou. První ze dvou čísel může být záporné, poté se opět počítá od konce řetězce
- zadání rozmezím dvou celých čísel, kdy rozmezí funguje stejně jako u první možnosti
1 2 3 |
puts "ahoj svete".slice(0, 4) #vraci ahoj puts "ahoj svete".slice(-3, 6) #vraci ete puts "ahoj svete".slice(0..4) #vraci ahoj |
Ořezat tedy můžeme řetězec jednoduše, ale co když chceme jeho část vymazat a neznáme rozmezí, ale obsah právě té části, kterou chceme z řetězce odstranit – právě k tomu účelu nám slouží funkce delete.
Jako parametr můžeme zadat podobně jako ve funkci squeeze buď řetězec, nebo rozmezí znaků, nebo řetězců, které chceme vymazat. Funkce vrací nový řetězec, který již požadovanou část neobsahuje:
1 2 |
puts "ahoj svete".delete("ahoj ") #vraci svete puts "ahoj ahoj".delete("a-j") #vraci o o |
Pro práci s řetězci existuje další spousta funkcí, ke kterým se postupně dostaneme s dalšími a dalšími vědomostmi. Prozatím si vystačíme s tímto základem.
Tesil jsem se, ze se treba dozvim neco vic o RoR, ale 7 dilu a zatim jen datove typy ruby…bude nekdy i RoR? 🙂
Postupne, hned po Ruby.