abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Sledujte AbcLinuxu.cz na:
facebook favicon logo  Facebooku twitter favicon logo  Twitteru,   identi.ca favicon logo  Identi.ca,   rss logo  RSS
Rozšířené hledání
×
včera 22:22 | Zajímavý software
Webový prohlížeč Chrome v budoucnu asi nebude mít podporu pro online ověřování, zda nebyl HTTPS certifikát revokován (CRL). V odkazovaném článku je uvedeno několik důvodů pro tento krok, zejména pak to, že toto ověřování nemusí být spolehlivé a zpomaluje načítání stránek. Namísto toho je navrhována distribuce revokovaných klíčů přes aktualizační mechanismus prohlížeče.
Luboš Doležel (Doli) | Komentářů: 2
včera 22:18 | Zajímavý projekt
Grafický server Wayland, možný nástupce současného X Serveru, se své první stabilní verze 1.0 dočká možná už v druhé polovině tohoto roku, nejpozději však za rok. Tento plán prezentoval tvůrce Waylandu Kristian Høgsberg na konferenci FOSDEM, která během uplynulého víkendu probíhala v Bruselu.
Migilenik | Komentářů: 1
včera 22:17 | Pozvánky

Ve středu 15.2. od 18:00 proběhne na Fakultě informatiky Masarykovy univerzity v Brně únorové setkání Czech JBoss User Group. Tentokrát bude tématem vytváření opravdových Java EE aplikací s JBoss AS. Zahraničním hostem bude Pete Muir, který posluchačům ukáže, jak se taková aplikace vytváří. Více informací na wiki stránce akce.

Sešívaný | Komentářů: 0
včera 22:17 | Zajímavý projekt
Díky pomoci ze strany Google se v posledních pár dnech podařilo sepsat příručku pro začínající vývojáře v prostředí KDE. Tato kniha je dostupná nejen v podobě PDF/ePub, ale i v tištěné podobě.
Luboš Doležel (Doli) | Komentářů: 0
včera 22:14 | Zajímavý projekt
První hromadně vyráběné kousky laciného ARM minipočítače Raspberry Pi budou zhotoveny 20. února. Hned poté se započne s přepravou do Velké Británie, takže prodej by měl začít do konce měsíce. Druhou novinkou je zveřejnění datasheetu k SoC BCM2835, které je hlavním stavebním kamenem Raspberry Pi.
Luboš Doležel (Doli) | Komentářů: 0
včera 14:34 | Nová verze
Vyšla nová stabilní verze populárního ruského webového serveru nginx – 1.0.12. Seznam změn hovoří zejména o opravě několika chyb. Nově je možné v konfiguraci specifikovat verzi TLS u direktivy ssl_protocols a SSI příkaz if podporuje pojmenované zachycení (tzv. capture) v regulárních výrazech.
MMMMMMMMM | Komentářů: 5
včera 12:36 | Komunita
Phoronix upozorňuje, že svobodný ovladač Nouveau má funkční podporu pro OpenCL. Úvodní podpora se týká ovladače pro čipy NV50, tedy grafické karty GeForce 8, 9, 100, 200 a 300. Kód je zatím udržován v samostatné větvi.
Nicky726 | Komentářů: 2
včera 12:26 | Komunita
Vývojář Kubuntu Jonathan Riddell oznámil, že Canonical končí s financováním Kubuntu. Kubuntu tak bude komunitní distribucí jako jiné deriváty Ubuntu, skončí i možnost placené podpory a Jonathan se nebude moct ve své pracovní době věnovat Kubuntu.
Nicky726 | Komentářů: 46
včera 00:12 | Nová verze
Vyšla nová vanilla linuxová jádra 3.0.20 a 3.2.5. Přidán byl jediný patch, který upravuje nastavení ASPM (Active State Power Management) a tím snižuje spotřebu linuxového jádra. Posouzení nutnosti aktualizace nechává Greg Kroah-Hartman tentokrát na uživatelích.
Ladislav Hagara | Komentářů: 17
6.2. 22:56 | Nová verze
V Beta Channel se objevil Firefox 11 přinášející zajímavé novinky. Vylepšený Migration Tool nově umožňuje import informací i z prohlížeče Google Chrome, Firefox Sync zase (skrze Add-on Sync) synchronizaci doplňků mezi různými instalacemi Firefoxu. Přibyla i podpora protokolu SPDY. Vývojáře bude zajímat především nový 3D Web Inspector, který vznikl implementací rozšíření Tilt.
Migilenik | Komentářů: 0
Servery pro sdílení souborů (typu MegaUpload)
 (40%)
 (49%)
 (11%)
Celkem 498 hlasů
 Komentářů: 29, poslední včera 08:38
Rozcestník
Reklama
Autoškola testy online Levný benzín

Ruby pro začátečníky - 6 (regulární výrazy)

9. 8. 2006 | Jaromír Hradílek | Programování | 6483×

Dnes si stručně ukážeme, co to jsou regulární výrazy, a jak je v Ruby použít.

Obsah

1. Stručný úvod
2. Operátor =~
3. Metoda sub (sub!)
4. Metoda gsub (gsub!)
5. Pamatování si vyhovujících řetězců

1. Stručný úvod

Jste-li uživatelem Linuxu nebo jiného systému unixového typu a nebojíte se příkazové řádky, pravděpodobně jste se už s regulárními výrazy setkali. Využívá jich napřiklad streamový editor sed, vyhledávací program grep a spousta textových editorů (vim, kate) a dalších programů (less, awk). Regulární výraz je jakýsi vzor, podle nějž se vyhledává řetězec v textu, obvykle za účelem provedení nějaké operace, typicky náhrady za jiný řetězec nebo extrakce určitých údajů.

Regulární výrazy jsou samy o sobě látkou dosti obsáhlou a jejich detailní výuka není účelem tohoto seriálu – od toho jsou zde povolanější, například vynikající seriál Pavla SatrapyRegulární výrazy. Pokud jste se s nimi tedy dosud nesetkali, doporučuji po přečtení tohoto článku prostudovat výše zmíněné materiály. Ačkoli jejich zvládnutí není pro další pokračování v jazyku Ruby nezbytné, jejich ignorací se připravíte o velmi silný nástroj, a to nejen v Ruby.

Jak už jsem řekl v úvodu, regulární výraz je vlastně vzor pro vyhledávání v textu a v jazyce Ruby se uzavírá mezi dopředná lomítka /. Nejjednodušším vzorem je libovolný znak, tyto znaky pak lze zřetězit do slov:

/a/     # Tomuto vzoru vyhovuje libovolný výskyt písmene a.
/ahoj/  # Tomuto vzoru vyhovuje libovolný výskyt slova ahoj.
/1984/  # Tomuto vzoru vyhovuje libovolný výskyt čísla 1984.

Je třeba podotknout, že regulární výrazy jsou ve výchozím stavu case-sensitive, tedy rozlišující velikost písmen. Výrazu /ahoj/ tedy vyhovuje ahoj, zatímco Ahoj nebo AHOJ už ne.

Toto dozajista není nijak zvlášť oslňující. Pravá kouzla však přichází až s výčtem speciálních vzorů, které Ruby rozeznává:

zápis: význam:
[] Výčet znaků, které se mohou na daném místě vyskytovat, včetně rozsahů.
Např. [a-z] vyhovuje všem znakům malé (anglické) abecedy, [Aa] vyhovuje malému i velkému písmenu a.
^ Uvedena jako první znak výrazu zastupuje začátek řádku.
Uvedena bezprostředně za otevírací hranatou závorkou výčtu plní funkci negace, např. [^a] vyhovuje jakémukoli znaku krom malého a.
$ Uveden na konci regulárního výrazu zastupuje konec řádku.
\w Libovolný alfanumerický znak. Ekvivalentní zápisu [a-zA-Z0-9]
\W Cokoli jiného než alfanumerický znak. Ekvivalentní zápisu [^a-zA-Z0-9]
\s Tzv. bílý znak, tedy mezera, tabulátor, nový řádek,… Ekvivalentní [ \t\n\r\f]
\S Cokoli jiného než bílý znak. Ekvivalentní [^ \t\n\r\f]
\d Libovolná jedna cifra. Ekvivalentní [0-9]
\D Cokoli jiného než numerický znak. Ekvivalentní [^0-9]
. Libovolný jeden znak.
* Žádný nebo libovolný počet výskytů předchozího znaku.
+ Jeden nebo libovolný počet výskytů předchozího znaku.
? Žádný nebo jeden výskyt předchozího znaku.
{m,n} Nejméně m, nejvýše n výskytů předchozího znaku.
| Slouží jako logické nebo.
Např.: /maly|velky/ vyhovuje řetězci maly, ale také velky
() Slouží k seskupování znaků, např. /(ha)+/ vyhovuje ha, haha atd.
Text vyhovující výrazu v závorkách je zároveň ukládán do paměti, viz dále.

Jakkoli to zpočátku vypadá komplikovaně, když vám přejdou do krve, stanou se regulární výrazy vítaným pomocníkem, a to zdaleka nejen v Ruby. A abychom nezůstali jen u teorie, pojďme se společně podívat na několik ukázek použití.

Řekněme, že chceme v konfiguračním souboru lokalizovat IP adresu. IPv4 se skládá ze čtyř čísel v rozsahu od 0 do 255, vzájemně oddělených tečkami (např. 192.168.1.3). Způsobů, jak napsat vyhovující vzor, je pochopitelně více, uveďme si jen pár z nich:

/\d+\.\d+\.\d+\.\d+/                              # Nepřesné.
/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/              # Lepší.
/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/  # Extrém!

První případ je jednoduchý a stručný, není však dostatečně přesný, vzoru totiž vyhoví i neplatná adresa (např. 192.1689.1.3), často však postačí. Druhý příklad je už přísnější, ačkoli stále připouští neplatné adresy, kdy cifra přesahuje 255 (např. 192.999.1.3), což se dá ovšem snadno ošetřit dále v programu. Třetí příklad je přepisem druhého aby bylo vidět, že to lze i složitěji.

Povšimněte si, že před každou tečkou je zpětné lomítko. Samostatná tečka má totiž ve výrazu význam libovolného znaku. Předcházejícím zpětným lomítkem explicitně říkáme, že chceme skutečně tečku. Podobně bychom postupovali i v případě ostatních rezervovaných znaků, včetně zpětného lomítka:

/\d+\s*\+\s*\d\s*=\s*\d+/   # Vyhovuje zápisu součtu dvou čísel, např.:
                            # 15 + 9 = 24
/[a-zA-Z]:\\/               # Vyhovuje uživatelskému promptu Windows,
                            # např.: C:\
/\*[A-Z][A-Z ]+\*/          # Vyhovuje textovým ICQ5 emotikonám, např.:
                            # *THUMBS UP* nebo *JOKINGLY*

Říkal jsem, že Ruby implicitně rozlišuje velikost písmen. Co když ale nevíme, jakým způsobem bude daný text zapsán (typicky přípony souborů stažených z internetu)? Představme si, že máme soubor, kde je na každém řádku uveden název souboru a my chceme vyhledat jen ty ve formátu Ogg Vorbis. Jednou z možností by bylo uvést všechny možnosti:

/^[\w ]+.[Oo][Gg][Gg]/

Toto je sice v případě třípísmenné přípony ještě únosné, kdybychom ale hledali delší text, asi bychom se uzávorkovali. Ruby naštěstí umožňuje rozlišování velikosti písmen explicitně vypnout a to uvedením volby i (case insensitive), již zapisujeme za uzavírací lomítko:

/^[\w ]+.ogg/i

Přehlednější, že ano?

2. Operátor =~

Po zvládnutí základů je na čase ukázat si, jak jich využít přímo v jazyce. Velmi často se používá operátor =~ který zjistí, zda se v řetězci vyskytuje nějaká část vyhovující vzoru. Pokud ano, vrátí číselný index prvního znaku nalezeného řetězce, v opačném případě vrátí hodnotu nil. Ukažme si to třeba na našem příkladu s ICQ emotikony:

irb(main):001:0> "tak to uz je spatny*TIRED*:-P" =~ /\*[A-Z][A-Z ]+\*/
=> 19
irb(main):002:0> ":-* ;-) :-*" =~ /\*[A-Z][A-Z ]+\*/
=> nil
irb(main):003:0>

Protože jako false je v Ruby krom false samotného vyhodnoceno už jen nil a cokoli jiného se automaticky vyhodnocuje jako true, lze operátor =~ bez obav použít k větvení programu:

irb(main):003:0> my_ip = "192.168.1.3"
=> "192.168.1.3"
irb(main):004:0> if my_ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
irb(main):005:1>   puts "Ok."
irb(main):006:1> else
irb(main):007:1*   print "Zadejte prosim svou IP: "
irb(main):008:1>   my_ip = gets.chomp
irb(main):009:1> end
Ok.
=> nil
irb(main):010:0>

Tento příklad má jednu vadu a to tu, že dále nezkoumá uživatelský vstup. To řeší třeba následující ukázka s cyklem:

irb(main):010:0> my_ip = ""
=> ""
irb(main):011:0> until my_ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
irb(main):012:1>   print "Zadejte prosim svou IP: "
irb(main):013:1>   my_ip = gets.chomp
irb(main):014:1> end
Zadejte prosim svou IP: Nepovim. :-P
Zadejte prosim svou IP: localhost
Zadejte prosim svou IP: 192.168.1.3    
=> nil
irb(main):015:0> puts my_ip
192.168.1.3
=> nil
irb(main):016:0>

A když už jsme u těch řídících struktur, byla by škoda si neukázat, že lze regulární výrazy bez obav použít i v konstrukci case:

irb(main):016:0> vypocet = "19 - 7 = 12"
=> "19 - 7 = 12"
irb(main):017:0> case vypocet
irb(main):018:1>   when /\d+\s*\+\s*\d\s*=\s*\d+/
irb(main):019:1>     puts "Soucet."
irb(main):020:1>   when /\d+\s*-\s*\d\s*=\s*\d+/
irb(main):021:1>     puts "Rozdil."
irb(main):022:1>   when /\d+\s*\*\s*\d\s*=\s*\d+/
irb(main):023:1>     puts "Soucin."
irb(main):024:1>   when /\d+\s*[:\/]\s*\d\s*=\s*\d+/
irb(main):025:1>     puts "Podil."
irb(main):026:1>   else
irb(main):027:1*     puts "Juj, tak ted jsi me dostal. :-o"
irb(main):028:1> end
Rozdil.
=> nil
irb(main):029:0>

3. Metoda sub (sub!)

Dalším běžným úkonem bývá náhrada textu za jiný. Pro datový typ String je proto definována metoda sub, jejíž zápis je následující:

řetězec.sub(vzor, náhrada)

Představte si, že chcete přenést skript pro nastavení pravidel iptables ze svého laptopu s Debianem na PC se Slackware. Jenže ejhle, všude voláte iptables s absolutní cestou a ta je ve Slackware jiná. Necháme-li stranou, že by byl na takový úkon patrně vhodnější sed (nebo mít ve skriptu cestu uloženou v proměnné), mohla by část vykonávající náhradu vypadat třeba takto:

irb(main):029:0> radek = "/sbin/iptables -A INPUT -i $IN -p tcp --syn -j dos"
=> "/sbin/iptables -A INPUT -i $IN -p tcp --syn -j dos"
irb(main):030:0> radek.sub(/\/sbin\/iptables/, "/usr/sbin/iptables")
=> "/usr/sbin/iptables -A INPUT -i $IN -p tcp --syn -j dos"
irb(main):031:0>

Teoreticky tedy procházíme skript, kdy každý řádek načítáme do proměnné radek a tu pak zpracováváme. Metoda sub nám nicméně obsah proměnné nemění, pozměněný řetězec předává jako návratovou hodnotu. Kdybychom chtěli záměnu aplikovat přímo na proměnnou, použijeme verzi s vykřičníkem:

irb(main):031:0> radek.sub!(/\/sbin\/iptables/, "/usr/sbin/iptables")
=> "/usr/sbin/iptables -A INPUT -i $IN -p tcp --syn -j dos"
irb(main):032:0> puts radek
/usr/sbin/iptables -A INPUT -i $IN -p tcp --syn -j dos
=> nil
irb(main):033:0>

4. Metoda gsub (gsub!)

Metoda sub má jen jednu „nevýhodu“ – uplatňuje se pouze na první výskyt vyhovujícího řetězce:

irb(main):033:0> ":p :p :p".sub(/:p/, ":-P")
=> ":-P :p :p"
irb(main):034:0>

Jsou situace, kdy nám to nevadí nebo toho s výhodou využijeme, jindy se nám to ale nemusí vůbec hodit. Naštěstí existuje metoda gsub, která provede náhradu všech řetězců vyhovujících vzoru:

irb(main):034:0> ":p :p :p".gsub(/:p/, ":-P")
=> ":-P :-P :-P"
irb(main):035:0>

Stejně jako v případě sub má i gsub variantu s vykřičníkem.

5. Pamatování si vyhovujících řetězců

V tabulce jsem se u závorek zmiňoval, že řetězec vyhovující vzoru mezi nimi je ukládán do paměti. Existují dva způsoby, jak se k nim dostat, a prvním z nich je prostřednictvím proměnné $n, kde n je číslo udávající pořadí závorek:

irb(main):035:0> udaj = "NAME=Feyd-Rautha Harkonnen"
=> "NAME=Feyd-Rautha Harkonnen"
irb(main):036:0> if udaj =~ /^NAME=([^ ]+) (.*)$/
irb(main):037:1>   puts "Krestni jmeno: " + $1
irb(main):038:1>   puts "Prijmeni:      " + $2
irb(main):039:1> end
Krestni jmeno: Feyd-Rautha
Prijmeni:      Harkonnen
=> nil
irb(main):040:0>

Druhý způsob – zápis ve tvaru \n – se používá přímo v regulárních výrazech. Dejme tomu, že máme v textovém souboru seznam jmen ve tvaru jméno příjmení, ovšem kvůli snazšímu vyhledávání bychom chtěli příjmení na prvním místě. Toho dosáhneme třeba takto:

irb(main):040:0> jmeno = "John Ronald Reuel Tolkien"
=> "John Ronald Reuel Tolkien"
irb(main):041:0> jmeno.sub!(/^(.*) ([^ ]+)$/, '\2 \1')
=> "Tolkien John Ronald Reuel"
irb(main):042:0>

Nejčtenější články posledního měsíce

Komiks xkcd 984: Space Launch System
Komiks xkcd 1001: ÁÁÁÁÁÁ
Komiks xkcd 983: Soukromí

Nejkomentovanější články posledního měsíce

Wine pro pokročilé
Programování v jazyce D (3): Typy, proměnné, práce s čísly, literály a funkce
Komiks xkcd 1010: Etymoloman
  všechny statistiky »

Seriál Ruby pro začátečníky (dílů: 8)

Ruby pro začátečníky - 1 (první díl)
<—« Ruby pro začátečníky - 5 (řídící struktury)
»—> Ruby pro začátečníky - 7 (metody a třídy)
Ruby pro začátečníky - 8 (soubory, výjimky, kontakt s OS) (poslední díl)

Související články

Ruby pro začátečníky - 1
Ruby pro začátečníky - 2 (komentáře, aritmetika, proměnné)
Ruby pro začátečníky - 3 (datové typy)
Ruby pro začátečníky - 4 (vstup, výstup)
Ruby pro začátečníky - 5 (řídící struktury)
Seriál: BASH
Python a PyQt - 1 (úvod)
Python a PyQt - 2 (podmínky, cykly, tlačítka)
Začínáme programovat v jazyce Python
Kommander - 1 (Skriptované GUI)
Kommander - 2 (Starý parser)
Kommander - 3 (Nový parser)
Seriál: Začíname KProgramovať
Programujeme v PERLu - I
Programujeme v PERLu - II

Další články z této rubriky

Programování v jazyce D (3): Typy, proměnné, práce s čísly, literály a funkce
Programování v jazyce D (2): Instalace, nastavení, první programy
Google Go – 2. narozeniny
Google Go – pravidla reflexe
Java Native Interface: vytváříme virtuální stroj
       

Hodnocení: 75 %

        špatnédobré        

Nástroje: Tisk bez diskuse

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Vložit další komentář

Marek Bernát avatar 9.8.2006 07:06 Marek Bernát | skóre: 17 | blog: Arcadia
Rozbalit Rozbalit vše Re: Ruby pro začátečníky - 6 (regulární výrazy)
Chápem, že regulárne výrazy sú dôležité, ale neviem prečo treba ich základy duplikovať do každého tutoriálu o programovacích jazykoch. Nebolo by lepšie dať odkaz na (lepší) tutoriál pre regulárne výrazy a zamerať sa len na špecifické operácie konkrétneho jazyka?

Poprosím len koštruktívne komentáre, toto má byť návrh na vylepšenie, ak to nie je zrejmé.
physics.stackexchange.com -- Q&A stránky o fyzike v štýle StackOverflow.
9.8.2006 09:52 Robert Krátký | skóre: 94 | blog: Robertův bloček | Praha
Rozbalit Rozbalit vše Re: Ruby pro začátečníky - 6 (regulární výrazy)
Nebolo by lepšie dať odkaz na (lepší) tutoriál pre regulárne výrazy a zamerať sa len na špecifické operácie konkrétneho jazyka?
Mám za to, že to takhle článek udělal. Lehký úvod do problematiky, seznámení, odkaz na tutoriál a popis toho, jak výrazy používat v Ruby (zkratky, operátory atd.).
Marek Bernát avatar 9.8.2006 20:15 Marek Bernát | skóre: 17 | blog: Arcadia
Rozbalit Rozbalit vše Re: Ruby pro začátečníky - 6 (regulární výrazy)
Ospravedlňujem sa autorovi, tú linku som prehliadol :-(
physics.stackexchange.com -- Q&A stránky o fyzike v štýle StackOverflow.
17.8.2006 13:28 Miroslav Pecka
Rozbalit Rozbalit vše Re: Ruby pro začátečníky - 6 (regulární výrazy)
Téměř vše o regulárních výrazech (články, hotová řešení, testery, diskuzní fórum) najdete na webu Regulární výrazy.

Založit nové vláknoNahoru

ISSN 1214-1267   Powered by Hosting 90 Server hosting
© 1999-2011 Argonit s. r. o. Všechna práva vyhrazena.