abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    včera 20:55 | Nová verze

    Homebrew (Wikipedie), správce balíčků pro macOS a od verze 2.0.0 také pro Linux, byl vydán ve verzi 4.5.0. Na stránce Homebrew Formulae lze procházet seznamem balíčků. K dispozici jsou také různé statistiky.

    Ladislav Hagara | Komentářů: 0
    včera 16:22 | Nová verze

    Byl vydán Mozilla Firefox 138.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 138 je již k dispozici také na Flathubu a Snapcraftu.

    Ladislav Hagara | Komentářů: 0
    včera 15:55 | Pozvánky

    Šestnáctý ročník ne-konference jOpenSpace se koná 3. – 5. října 2025 v Hotelu Antoň v Telči. Pro účast je potřeba vyplnit registrační formulář. Ne-konference neznamená, že se organizátorům nechce připravovat program, ale naopak dává prostor všem pozvaným, aby si program sami složili z toho nejzajímavějšího, čím se v poslední době zabývají nebo co je oslovilo. Obsah, který vytvářejí všichni účastníci, se skládá z desetiminutových

    … více »
    Zdenek H. | Komentářů: 1
    včera 15:44 | IT novinky Ladislav Hagara | Komentářů: 2
    včera 13:55 | Komunita

    Richard Stallman přednáší ve středu 7. května od 16:30 na Technické univerzitě v Liberci o vlivu technologií na svobodu. Přednáška je určená jak odborné tak laické veřejnosti.

    Ladislav Hagara | Komentářů: 8
    28.4. 23:33 | Nová verze

    Jean-Baptiste Mardelle se v příspěvku na blogu rozepsal o novinkám v nejnovější verzi 25.04.0 editoru videa Kdenlive (Wikipedie). Ke stažení také na Flathubu.

    Ladislav Hagara | Komentářů: 0
    28.4. 17:22 | Zajímavý projekt

    TmuxAI (GitHub) je AI asistent pro práci v terminálu. Vyžaduje účet na OpenRouter.

    Ladislav Hagara | Komentářů: 0
    28.4. 17:00 | Nová verze

    Byla vydána nová verze R14.1.4 desktopového prostředí Trinity Desktop Environment (TDE, fork KDE 3.5, Wikipedie). Přehled novinek i s náhledy v poznámkách k vydání. Podrobný přehled v Changelogu.

    Ladislav Hagara | Komentářů: 5
    27.4. 21:33 | Nová verze Ladislav Hagara | Komentářů: 0
    26.4. 23:00 | Komunita

    V Tiraně proběhl letošní Linux App Summit (LAS) (Mastodon). Zatím nesestříhané videozáznamy přednášek jsou k dispozici na YouTube.

    Ladislav Hagara | Komentářů: 0
    Jaký filesystém primárně používáte?
     (58%)
     (1%)
     (9%)
     (21%)
     (4%)
     (1%)
     (2%)
     (0%)
     (1%)
     (3%)
    Celkem 482 hlasů
     Komentářů: 18, poslední 17.4. 12:41
    Rozcestník

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

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

    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>
           

    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
    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   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.