Portál AbcLinuxu, 8. května 2025 23:23
Dnes, 27.9.2014, slaví životní jubileum Larry Wall, jeden z největších programátorů historie. Evropské oslavy tohoto významného jubilea se konají dnes v obci Perl, která sousedí s městečkem Schengen na hranici mezi Sárskem a Lucemburskem. Laudatio pronesou pánové Guido van Rossum a Yukihiro Matsumoto. :-)
Tiskni
Sdílej:
jeden z největších programátorů
největších? na výšku nebo na šířku?
Když řešíš složitou úlohu, tak si zkompiluj nějakou gramatiku, vyrob si speciální parser… ale na spoustu věcí je to zbytečnost nebo je to i v daném kontextu nepoužitelné – a tam se právě hodí regulární výrazy.
Já to prostě neberu jako problém – ale jako šikovný nástroj, který mi na jednom řádku nebo v pár znacích umožňuje udělat dost práce – což by se jinde řešilo mnohem složitěji. Samozřejmě to má svoje limity a ne všechno jde pomocí regexů vyřešit nebo vyřešit dobře.
Zajimave je, ze o odstavec niz v podstate stejny pristup komentujes jako "rozumny".Uniká mi, co je na tom tak zajímavé.
Bohuzel ale, syntaxe regexpu prirozene vede na copy/paste metodiku prace s nimi, a znovuvynalezani kola (psani dokolecka neuplnych parseru veci, ktere uz byly milionkrat predtim naparsovany).Obávám se, že copy/paste je vlastností člověka, nikoliv nástroje.
Ale jako regulérní součást zdrojového kódu programumy delamne s perlem od roku 1997 a skutecne jsme meli zpocatku regularni vyrazy ve zdojacich primo v kodu. Zkusenosti nas naucily, ze je vhodnejsi uz jen trochu komplikovanejsi nahrazovani dat do samostatnych subroutin, protoze ne kazdy okamzite na prvni pohled rozezna, co regexp vlastne dela. Takze dnes mame vlastni moduly, ktere obsahuji odzkousene regexpy a to uz i napr. odriznuti blanku zleva nebo zprava je regexp v subroutine. Ve zdrojovem kodu zustava jen skutecne zcela jasne nahrazovani neceho za neco.
Zkusenosti nas naucily, ze je vhodnejsi uz jen trochu komplikovanejsi nahrazovani dat do samostatnych subroutin, protoze ne kazdy okamzite na prvni pohled rozezna, co regexp vlastne dela.Jo, to zní velice rozumně.
Dík za typ, ale rozmýšľal som nad tým, že prečo niekto odmieta jednoznačne dobrú technológiu.Už asi dvakrát jsem se ptal, na konkrétní příklad, kdy je teda tahle technologie jednoznačně dobrá...
<img src="..." alt="nefunguje">
<img src='nefunguje'>
<img src="nefunguje" />
<img src="nefunguje"><img src="idelendruhy">
...
Tak nějak. Buď vím, co je na vstupu a že mi regex bude fungovat → pak je jeho použití v pohodě, přináší hodně užitku. Nebo hledám univerzální a neprůstřelné řešení a pak použiji již hotový parser + XPath nebo XSLT.
XPath / XSLT by na tento prípad nebolo použiteľné. Na korektné parsovanie HTML sa používa skutočná knižnica na HTML (HTML != XML).
Nikoliv. Libovolný formát (klidně i binární nebo třeba ten HTML hnůj) můžeš s vhodným parserem převést na SAX události, postavit z toho DOM a nad tím pustit XPath nebo XSLT. Ostatně přijď na OpenAlt konferenci
Veď práve o to ide, že treba použiť ďalší nástroj pretože HTML5 má k xml na míle ďaleko (neviem čo požrali tí, čo ho navrhovali ale chcem aj ja). OpenAlt sa mi prekrýva s fotografickým workshopom.
Veď práve o to ide, že treba použiť ďalší nástrojAni to nemusí být vždy pravda, používal jsem nějakou XML knihovnu, která v sobě měla i HTML parser.
Aký nástroj zvláda parsovať toto? Však to nezvládam ani ja.
</HTML></head>
To, že něco nejde parsovat jako XML (třeba protože to není XML), ještě neznamená, že to nejde zpracovávat jako XML.Teď nevím, jestli to myslíš vážně, nebo jestli to je černý humor
Na tom už nesejde – i jiné formáty se dají převést na SAX/DOM…
Dík za nahrávku na smeč. Presne kvôli tomu dovolím len tento jediný zápis obrázku. Takže sa budem opakovať, je to o štýle písania a použitia technológií.Je to hack a prasárna. Ano, podobné regexpy používám čas od času taky, ale "jednoznačně dobrou" technologii bych to teda rozhodně neoznačil...
Vždy je to korektnejšie správanie pokiaľ spracuješ len to čo chceš ako Bistrouškove nedefinované stavy pri konverzií z eBook do eBook čo má v blogu. Za prasárnu považujem to keď je tam vedome možnosť dosiahnuť nedefinované stavy.Tam imho nejsou nedefinované stavy, ale XML v rozporu s tím, co definuje EPUB standard. Samozřejmě, pokud bych to dělal nějak komerčně, či nad tím stavěl produkt, tak implementuji vše tak jak se má. Já ale nechtěl dokonalý nástroj, chtěl jsem ten web korektně v epubu a i tak jsem na tom zabil až moc času (odpoledne a kus večera).
Keď rozmýšľam ako by mal nejaký projekt vyzerať, tak si to napríklad zjednoduším tým že povolím len určitý vstup, je to hlavne kvôli bezpečnosti a pri nezhode sa snažím vyhodiť nápovedu, aby užívateľ neostal mimo.Jo, oblíbenou zábavou je potom pustit na to fuzzer a snažit se ten regexp zbořit. Rozhodně by to nebyl první ani poslední regexp použitý k bezpečnosti, který někdo znásilnil a proklouzl přes něj jak nic.
Můžeš dát nějaký příklad (pokudmožno konkrétní), na co je regexp dobrý?
Z praxe? Třeba směrování SMSek na základě regulárních výrazů nebo provádění různých akcí na základě toho, co regulární výraz našel. Uživatel ti tam nebude psát žádný kód parseru v Pythonu, prostě zadá regulární výraz.
Další věc jsou různé validace – na ty základní stačí zadat regulární výraz, není potřeba nic programovat. Složitější můžeš udělat tak, že regexem vytáhneš z textu skupiny a zvaliduješ vztahy mezi nimi. A až ty nejsožitější budeš řešit procedurálně nebo tvorbou vlastní gramatiky. Třeba když potřebuješ během validace posílat DNS dotazy nebo se dívat do databáze, to fakt regexpy nesvedou. Nebo když je vstupem složitý jazyk.
A pak takové běžné transformace textu nebo hledání – všechny ty grep
y a sed
y, které se každý den používají. Nebo jednořádkové „skripty“ v Perlu – vytahat z textu skupiny a nějak je přeskládat na výstup, sem tam něco spočítat nebo prohnat nějakou funkcí.
Případně prasárny typu transformace/úprava HTML – na to jsou obecně lepší nástroje (parser + XPath nebo XSLT), ale když máš ten vstup pod kontrolou a používáš jen podmnožinu HTML/XML, tak se to dá zpracovat i tím regulárním výrazem – nedávno jsem např. převáděl seznamy literatury ve tvaru nečíslovaných seznamů a odkazů na SQL INSERTy. Jako univerzální řešení by to bylo nepoužitelné, ale pro ad-hoc poloautomatickou konverzi je to hodně užitečný nástroj.
Další věc jsou různé validace – na ty základní stačí zadat regulární výraz, není potřeba nic programovat. Složitější můžeš udělat tak, že regexem vytáhneš z textu skupiny a zvaliduješ vztahy mezi nimi.No, na tohle se regexpy dost používaj, ale přitom jsou v podstatě k tomuhle naprosto nevhodný. Co zvaliduješ regexpem? V podstatě pouze triviální případy jako třeba přirozené číslo nebo něco takového. Ale jakmile potřebuješ validovat cokoli jen trošku složitějšího (např. IP adresu nebo něco podobného), už potřebuješ netriviální regexp + obslužný kód nebo rovnou jiný řešení... Ve výsledku je mnohem lepší nesnažit se vynálézat kolo krkolomnýmy regexpy a jejich ohýbáním a místo toho použít nějakou knihovnu na validaci různých věcí (existují pro všemožné jazyky/platformy).
ale když máš ten vstup pod kontrolou a používáš jen podmnožinu HTML/XML, tak se to dá zpracovat i tím regulárním výrazem – nedávno jsem např. převáděl seznamy literatury ve tvaru nečíslovaných seznamů a odkazů na SQL INSERTy. Jako univerzální řešení by to bylo nepoužitelné, ale pro ad-hoc poloautomatickou konverzi je to hodně užitečný nástroj.To souhlas...
místo toho použít nějakou knihovnu na validaci různých věcí (existují pro všemožné jazyky/platformy).
Jenže která z nich je obecně uznávaný standard?
Ono když děláš obecné řešení, tak potřebuješ ten validační předpis zadat jako parametr, ne tam psát kód a volat metody nějaké knihovny. A na tohle se mnohem víc hodí regex:
Validace se stejně obvykle dělají ve více krocích – nejdřív jednoduché, které probíhají klidně na klientovi, zkontroluje se počet znaků, zda je to číslo, text, mezery, povinné předpony atd. A v druhém kroku se řeší složitější věci jako vztahy mezi jednotlivými atributy (třeba políčka formuláře), referenční integrita, dohledávají se věci v relační databázi nebo třeba DNS, volají se nějaké procedury atd. Na ten první krok jsou regulární výrazy dobré řešení.
Když to shrnu, jaké máme možnosti:
Ten lepší jazyk je spíš v hypotetické rovině, konkrétní použitelné řešení jsem tu neviděl. Udělat gramatiku a parser bude často kanón na vrabce. Rozhodně to není nic, co bys zadal jako jeden krátký textový parametr. Procedurální přístup je někdy nevyhnutelný, ale dá se kombinovat s předchozími možnosti – pomocí regulárních výrazů nebo gramatiky dostaneš ze vstupu nějaké části, uzly atd. a ty procedurálně zpracuješ (třeba dohledáš v databázi).
Regulární výrazy nejsou vše-spásné nebo univerzální řešení, ale přesto je to dost užitečný nástroj a pro hodně úloh nejlepší řešení.
Jenže která z nich je obecně uznávaný standard?Nejspíš žádná, ale to regexp taky není. Zaprvý to není jazyk pro specifikaci validátorů a zadruhý každá implementace má své nuance.
Ono když děláš obecné řešení, tak potřebuješ ten validační předpis zadat jako parametr, ne tam psát kód a volat metody nějaké knihovny.A proč by ne? Když píšu aplikaci, tak je mnohem lepší udělat něco jako
validator.validateIPAddress(userInput);
než tam sr*t nějakej regexp, kterej bude na 99% a) hůř čitelnej a b) nebude dobře fungovat. A je celkem jedno, jestli se jedná o serverside nebo client side, to řešení s odladěnou knihovnou bude lepší skoro vždy...
validator.validateIPAddress(userInput)
by se tam spíš neměly objevit. Lepší návrh je rozhraní, které validuje, má metodu validate(…)
a až jedna z implementací tohoto rozhraní bude třeba IPAddressValidator
. A pak jenom řekneš, na která políčka se tenhle validátor má použít.
Jenže ty třeba nepíšeš, software – máš nějaký nainstalovaný a jen ho parametrizuješ. (...) Stačí parametrizovat obecný validátor.Obecný validátor asi těžko půjde parametrizovat regexpama.
nic neprogramuješ, jen parametrizuješVe chvíli, kdy píšeš regexp na validaci něčeho, v podstatě programuješ, navíc nástrojem IMHO ne moc vhodným pro daný úkol...
Ale když na to stačí regulární výraz, tak proč něco programovat?V případě toho kroku 1) asi celkem o nic nejde, vzhledem k tomu, že skutečná validace je v kroku 2), nicméně použití nějaký hotový knihovny mi přijde jednoduší... Věc názoru...
Metody jakoTo už mluvíš o implementačních detailech v konkrétním jazyce (asi v Javě). Jinak obecně je samozřejmě dobrý mít možnost říct, co se má validovat čím, to souhlasím...validator.validateIPAddress(userInput)
by se tam spíš neměly objevit. Lepší návrh je rozhraní, které validuje, má metoduvalidate(…)
a až jedna z implementací tohoto rozhraní bude třebaIPAddressValidator
. A pak jenom řekneš, na která políčka se tenhle validátor má použít.
Obecný validátor asi těžko půjde parametrizovat regexpama.Obecný v tom smyslu, že není pro konkrétní aplikaci nebo políčko formuláře – prostě obecný regexový validátor, kterým můžeš validovat PSČ, telefonní čísla, datum atd. to už je na tobě.
Ve chvíli, kdy píšeš regexp na validaci něčeho, v podstatě programuješ, navíc nástrojem IMHO ne moc vhodným pro daný úkol...Vhodný nástroj to IMHO je, protože plní účel, uživatel ten jazyk ovládá a je to o zadání jednoho textového řetězce (který nemusí být nijak složitý a přesto je k užitku). Padly tu nějaké výhrady, třeba že mezera je doslovně mezera a ne oddělovač tokenů v tom jazyce nebo, že se obecně většina znaků bere doslovně a jen \některé mají speciální význam – tzn. že by možná bylo lepší opačně, doslovné řetězce psát třeba do uvozovek, zatímco řídící znaky a operátory bez… Tyhle výhrady celkem beru, ale: kde je takový jazyk? Kde jsou knihovny pro něj, pro většinu platforem? Kde jsou uživatelé, kteří s tím budou umět pracovat?
V případě toho kroku 1) asi celkem o nic nejde, vzhledem k tomu, že skutečná validace je v kroku 2), nicméně použití nějaký hotový knihovny mi přijde jednoduší...A tu knihovnu si představuješ jak? Že v ní bude zrovna podpora pro typ atributu xyz, který je specifický pro tvoji aplikaci/firmu/obor a má mít 8-10 znaků, začínat na XY nebo ZW a nesmí obsahovat mezery, ale může obsahovat pomlčky?
Obecný v tom smyslu, že není pro konkrétní aplikaci nebo políčko formuláře – prostě obecný regexový validátor, kterým můžeš validovat PSČ, telefonní čísla, datum atd. to už je na tobě.Jj, však jo. Jak říkám, obecný validátor asi těžko definuješ regexpem. Například validátor data by měl přijmout datum
2000-02-29
a odmítnout 2100-02-29
. Moc nevidím, jak takový validátor definovat regexpem. Regexp by v tomhle případě pomohl nejspíše jen s tokenizací.
A tu knihovnu si představuješ jak? Že v ní bude zrovna podpora pro typ atributu xyz, který je specifický pro tvoji aplikaci/firmu/obor a má mít 8-10 znaků, začínat na XY nebo ZW a nesmí obsahovat mezery, ale může obsahovat pomlčky?Tyhle knihovny většinou obsahují nejčastěji používané typy, pro nějaké specifické typy/formáty vstupu většinou poskytují prostředky pro implemetaci validátoru, takže pro běžné věci nevynalézáš kolo a pro speciality si sice musíš napsat kód, ale ta knihovna to typicky ulehčuje.
Například validátor data by měl přijmout datum 2000-02-29 a odmítnout 2100-02-29.
To už je spíš úkol pro to druhé kolo validace. V tom prvním stačí eliminovat překlepy nebo třeba úplné nesmysly typu „nikdy“, „vloni“, „21. lenda“ atd. V tom druhém kole zjistíš, jestli ten den vůbec existuje, nebo jestli byl pracovní, pokud je to potřeba, nebo třeba jestli je v nějakém intervalu (třeba po datu vzniku uživatelského účtu – kvůli čemuž se musíš dívat do databáze a s tím ti žádný jednoduchý validátor nepomůže).
takže pro běžné věci nevynalézáš kolo a pro speciality si sice musíš napsat kód, ale ta knihovna to typicky ulehčuje.
Ano, a jedním ze způsobů, kterým ti to moje knihovna ulehčuje, je to, že má regexový validátor, který si snadno parametrizuješ + možnost napsat si validátor úplně vlastní, procedurálně.
To už je otázka, jak daleko chceš jít. Třeba u e-mailu:
Je jen na tobě resp. na požadavcích na aplikaci, co všechno budeš kontrolovat. Regulární výrazy hodně z toho nesvedou – ale hodně z toho neřeší ani běžně používané procedurální validátory nebo třeba gramatiky.
Mj. taky záleží, proč validuješ – jestli chceš mít v databázi jen 100% pravdivá data nebo proto, abys tam měl data zadaná uživateli, která nemusejí být úplně pravdivá, ale jsou to, co uživatel chtěl zadat. Buď uživatelům věříš nebo nemůžeš/nechceš řešit, co je „pravda“ a realita a prostě v tom systému připustíš hodnoty, které tam uživatelé vědomě chtějí. Ale nepřipustíš zjevně nesmyslné hodnoty, které tam uživatelé nechtějí a jen se spletli – např. když se vrátíme k těm e-mailům: hodně lidí si splete tečku a čárku nebo třeba tečku vynechají a v doménové části mají třeba gmailcom
nebo seznamcz
, což regulární výraz odhalí.
Další věc je formátování – např. můžeš podporovat různé formáty data a pomocí regulárního výrazu a skupin z toho vytáhnout rok, měsíc, den a následně převést na datum a pak třeba zkontrolovat, že je to existující datum. Regulárních výrazů můžeš mít víc, projdeš je v cyklu, zjistíš, který vyhovuje – a dál už ten kód bude stejný, protože všechny ty výrazy ti extrahují stejné pojmenované skupiny.
Regulárních výrazů můžeš mít víc, projdeš je v cyklu, zjistíš, který vyhovuje – a dál už ten kód bude stejný, protože všechny ty výrazy ti extrahují stejné pojmenované skupiny.+1 I když je pravda, že alternativy gramatikou bez problémů pokryješ.
Jj, však jo. Jak říkám, obecný validátor asi těžko definuješ regexpem. Například validátor data by měl přijmout datumJen?!2000-02-29
a odmítnout2100-02-29
. Moc nevidím, jak takový validátor definovat regexpem. Regexp by v tomhle případě pomohl nejspíše jen s tokenizací.
Například validátor data by měl přijmout datum 2000-02-29 a odmítnout 2100-02-29. Moc nevidím, jak takový validátor definovat regexpem.Taky ze sebe dokážu sypat příklady věcí, které regexp neumí, nakonec skončíme u vaření kafe. Zní to jako špatné přirovnání, ale ty si stěžuješ, že nástroj, který umí jakž takž validovat a parsovat nějaký formát, nemá v sobě integrovaný kalendář.
Tyhle knihovny většinou obsahují nejčastěji používané typy, pro nějaké specifické typy/formáty vstupu většinou poskytují prostředky pro implemetaci validátoru, takže pro běžné věci nevynalézáš kolo a pro speciality si sice musíš napsat kód, ale ta knihovna to typicky ulehčuje.Docela vágní (náznak) specifikace. Na tom bych asi kritiku pro jiné užitečného a užívaného nástroje nestavěl.
Zní to jako špatné přirovnání, ale ty si stěžuješ, že nástroj, který umí jakž takž validovat a parsovat nějaký formát, nemá v sobě integrovaný kalendář.Ale vůbec ne. Já si jen stěžuju, když se na validace používají nástroje, které nejsou na validaci ani určené, ani vhodné... (Do toho nepočítám situaci, kdy validátor používá regexp(y) pro tokenizaci...)
([0-9]{1,3}\.){3}[0-9]{1,3}Stejně tak když chceš odhalit nesmysly a překlepy. Nebo když chceš odfiltrovat nebezpečný vstup, abys tu hodnotu mohl předat někam dál. Stále jsou případy, kdy někdo neprovádí ani takovouhle kontrolu – ten regex by bezpečnostní problém vyřešil. Někdy se o tom rozepíšu víc… A že ti někam proleze IP adresa
123.456.789.123
? To zase není takový problém – pořád lepší, než aby tam prolezlo 127.0.0.1; wget -O - http://example.com/… | sh -s
IP adresa asi není ideální adept na kontrolu nebo parsování regexpem.Ano. Stejně jako řada dalších uživatelských vstupů...
Ještě jeden pěkný příklad – soubory, které se mají ignorovat při verzování:
$ cat .hgignore syntax: glob *~ syntax: regexp ^java/[^/]+/dist/ ^java/[^/]+/build/ ^java/[^/]+/nbproject/private/ ^documentation/.+\.(svg|png|ps|eps|pdf)$
V čem jiném bys to chtěl psát?
a:int a*:int a+:int, b:floatUdělám na to regexpr pro popis vzoru:
~([\w]+)([\+\*\?\.]?)\:([\w]+)~
a vzor pro oddělovače:
~[,;\s]+~
Každý vstup projdu nejdřív na oddělovače, a pak každý ten klíč rozeberu na potřebné sekce, ze kterých dál udělám objekt.
Toto celé otestuju, páč vám to tu píšu z hlavy, a zabalím do funkce, která přijímá string a vrací definici té typové deklarace.
Tento přístup mi přijde nejjednodužší, a přitom nejodolnější proti chybám.
V čem vidíte problém?
name = [a-zA-Z_0-9]+ @{ defObj.setName(p); }
flag = [+*?.]? @{ defObj.setFlag(p); }
type = [a-zA-Z_0-9]+ @{ defObj.setType(p); }
def = name flag ':' type
delim = ([,;] | space)+
main := (def delim)+
V těch složených závorkách je jen pseudokód, přišel by tam host code pro zpracování tokenu. Ragel ale bohužel nepodporuje žádné skriptovací jazyky krom Ruby... Jinak samozřemě i Ragel má své limitace/problémy...
No a jake jsou teda lepsi alternativy?To co píše xkucf03 nademnou - vyrobit si (třeba) BNF parser.
Vtip je mj. v tom, že regexpy jsou jakýsi společný jazyk, nejsou specifické[jasně, odlišnosti se najdou, ale ten základ je stejný] pro Perl, Javu, Python, Lisp atd. navíc PCRE jsou v různých jazycích. Takže se to dá použít i pro konfiguraci – administrátor prostě zadá regex, což umí a nemusí zadávat nějakou speciální gramatiku v jazyce, v kterém je psaná daná aplikace.
Zrovna ty pojmenované skupiny jsou šikovná věc – dá se tím dobře dělat konfigurace/parametrizace – pomocí výrazu vytaháš z textu skupiny a ty se nějak použijí – administrátor jen napíše ten výraz (regexpy obvykle umí na rozdíl od programování v jazyce XY).
Sam regexpy pouzivam, ale skutecne by bylo lepsi, kdyby je nahradilo neco citelnejsiho.Ja treba regualarni vyrazy pouzivam denne ve ViMu. V 99% jsou to jednorazove vyrazy, takze ukecanejsi syntaxe by jen zdrzovala a standardni knihovna by moc nepomohla. Hodne zalezi na tom, kde to potrebujes pouzivat.
A pouzivas v takove situaci vselijaka ta Perlova rozsireni, nebo jen klasiku operatory .,?,*Kdyz se divam do historie, tak pouzivam v drtive vetsine pripadu ., *, ?, +, [], [^], {,}, (), |.
nez to clovek vyladi, zda to hleda spravne to co chce, vyjde mu rychleji se vyporadat s nekolika vyjimkami, ktere to najde.Tohle nepozoruju.
A Perl ten tarpit zacal rozsirovat.Perl je by design slozity. Larry Wall ho navrhoval s tim, ze jeho vyjadrovaci schopnosti maji byt podobne beznemu jazyku, tj. muzes vyjadrit jednu vec ruznymi zpusoby. Vedlejsi efekt je, ze naucit se ten jazyk je stejne slozite, jako naucit se bezny jazyk.
Vetsinou kdyz jsem v shellu sahl k regularnim vyrazum (a mel jsem je slozitejsi nez by stacily wildcardy, navic Bashova rozsireni pro sekvence znaku jsou taky super), bylo to proto, ze jsem potreboval vytahnout neco z HTML.Parsovat HTML pomoci reg. vyrazu je blbost vzhledem ke slozitosti gramatiky, proto chapu, ze ti to prislo neohrabane a pouzil jsi radsi specializovany nastroj.
Tvuj use case ve VIMu je predpokladam programovaniNe nezbytne. Typicky problem jsou konverze dat mezi formaty. Napr. mam vystup z programu, vypis v podobe hodnot odsazenych taby, potrebuju z toho udelat SQL. Nebo mam poznamky v LaTeXu a potrebuju predelat \item na <li> a dalo by se pokracovat... Ano, mohl bych treba v tom druhem pripade napsat makra pro TeX, ktere to provedou taky, ale proc, kdyz muzu pouzivat mne zname prostredi na vsechno. Kdesi niz pises:
IMHO regexpy jsou klasickym pripadem "Worse is better"IMHO reg. vyrazy jsou "good enough". IMHO je to neco jako duct tape. Pro vetsinu problemu to neni idealni reseni, ale je to naprosto dostacujici reseni.
/[[:digit:]]{5,}/
vyhovuje hocijaký číselný kód minimálne s piatimi číslami. Domáca úloha napíš toto rovnako čitateľne a efektívne bez Regexp.
[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]Pak to pustíš, ono si to vesele běží a za půl roku zjistíš, že to nefunguje jak má. Tak to hackuješ a přidáváš.
^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$A ono se to zase rozbije. Tak se na to vykašleš, googlíš a zjistíš, že pokud to chceš dělat správně (což chceš, protože už máš dost toho se s tím pořád babrat) dle RFC 5322, tak potřebuješ tuhle obludu:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)* | "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f] | \\[\x01-\x09\x0b\x0c\x0e-\x7f])*") @ (?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])? | \[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3} (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]: (?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f] | \\[\x01-\x09\x0b\x0c\x0e-\x7f])+) \])Najít se ovšem dají i zábavnější:
(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t] )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?: \r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:( ?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0 31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\ ](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+ (?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?: (?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z |(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n) ?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\ r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n) ?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t] )*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])* )(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t] )+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*) *:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+ |\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r \n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?: \r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t ]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031 ]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\]( ?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(? :(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(? :\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(? :(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)? [ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]| \\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<> @,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|" (?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t] )*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\ ".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(? :[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[ \]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000- \031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|( ?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,; :\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([ ^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\" .\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\ ]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\ [\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\ r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\] |\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0 00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\ .|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@, ;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(? :[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])* (?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\". \[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[ ^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\] ]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*( ?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\ ".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:( ?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[ \["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t ])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t ])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(? :\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+| \Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?: [^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\ ]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n) ?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[" ()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n) ?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<> @,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@, ;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t] )*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\ ".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)? (?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\". \[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?: \r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[ "()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t]) *))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]) +|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\ .(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z |(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:( ?:\r\n)?[ \t])*))*)?;\s*)Když se na to podíváš, tak vůbec není vidět co to dělá. Potřeboval bych aspoň 30 minut, než bych tu sračku nastudoval a to by mi za tu dobu asi 7x přetekly nervy. Největší zábava ovšem je, pokud narazíš někde v knihovním kódu na někoho, kdo si myslí že regexpům rozumí, implementuje tím něco kritického a ty přijdeš na to, že je to rozbité, v nějakém procentě případů. Takový evergreen je třeba parsování HTML, což je ještě 10x komplikovanější, než kód nahoře. Ale kdo by to kdy nezkusil, vždyť jde přece o jeden jediný znak a kolik to ušetří výkonu, když se nemusí startovat parser! A ty se v tom pak máš hrabat a opravovat to, hledat chybu někde uprostřed té přerostlé sekvence náhodných znaků. Fuck this shit. Schválně si to srovnej s ABNF verzí a rozmysli si, jestli je pro tebe skutečně tak důležité šetřit místo na disku kompilováním do write-only jazyka, nebo nervy svoje a všech co to kdy budou číst po tobě:
addr-spec = local-part "@" domain local-part = dot-atom / quoted-string / obs-local-part dot-atom = [CFWS] dot-atom-text [CFWS] CFWS = (1*([FWS] comment) [FWS]) / FWS FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space WSP = SP / HTAB ; white space obs-FWS = 1*WSP *(CRLF 1*WSP) ctext = %d33-39 / ; Printable US-ASCII %d42-91 / ; characters not including %d93-126 / ; "(", ")", or "\" obs-ctext obs-ctext = obs-NO-WS-CTL ccontent = ctext / quoted-pair / comment comment = "(" *([FWS] ccontent) [FWS] ")" dot-atom-text = 1*atext *("." 1*atext) atext = ALPHA / DIGIT / ; Printable US-ASCII "!" / "#" / ; characters not including "$" / "%" / ; specials. Used for atoms. "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" specials = "(" / ")" / ; Special characters that do "<" / ">" / ; not appear in atext "[" / "]" / ":" / ";" / "@" / "\" / "," / "." / DQUOTE quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS] qcontent = qtext / quoted-pair qtext = %d33 / ; Printable US-ASCII %d35-91 / ; characters not including %d93-126 / ; "\" or the quote character obs-qtext obs-qtext = obs-NO-WS-CTL obs-NO-WS-CTL = %d1-8 / ; US-ASCII control %d11 / ; characters that do not %d12 / ; include the carriage %d14-31 / ; return, line feed, and %d127 ; white space characters quoted-pair = ("\" (VCHAR / WSP)) / obs-qp VCHAR = %x21-7E ; visible (printing) characters obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR) obs-local-part = word *("." word) word = atom / quoted-string atom = [CFWS] 1*atext [CFWS] domain = dot-atom / domain-literal / obs-domain domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS] dtext = %d33-90 / ; Printable US-ASCII %d94-126 / ; characters not including obs-dtext ; "[", "]", or "\" obs-dtext = obs-NO-WS-CTL / quoted-pair obs-domain = atom *("." atom) NB For SMTP mail, the domain-literal is restricted by RFC5321 as follows: Mailbox = Local-part "@" ( Domain / address-literal ) address-literal = "[" ( IPv4-address-literal / IPv6-address-literal / General-address-literal ) "]" IPv4-address-literal = Snum 3("." Snum) IPv6-address-literal = "IPv6:" IPv6-addr Snum = 1*3DIGIT ; representing a decimal integer ; value in the range 0 through 255 IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp IPv6-hex = 1*4HEXDIG IPv6-full = IPv6-hex 7(":" IPv6-hex) IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":" IPv6-hex)] ; The "::" represents at least 2 16-bit groups of ; zeros. No more than 6 groups in addition to the ; "::" may be present. IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::" [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal ; The "::" represents at least 2 16-bit groups of ; zeros. No more than 4 groups in addition to the ; "::" and IPv4-address-literal may be present.Ano, je to delší, ale zase kompletní (včetně například podpory IPv6 jako domény) a krásně čitelné i s komentáři. Cílem programu, speciálně v případě parseru, by nemělo být snažit se kód zkrátit na úkor čitelnosti. Od toho máme interpretry a kompilátory. *Přičemž složitost se podobně jako v umělé inteligenci nepočítá podle toho jak ti to přijde složité než se do toho pustíš, ale jak je to skutečně složité poté co to implementuješ, někdo to zboří, pak to třikrát ohackuješ, někdo to zboří, pak sepíšeš formální gramatiku a po roce to konečně funguje. PS: Všechny kódy slouží jen jako ilustrace, jejich korektnost jsem netestoval. Jedná se o reprodukci mých historických osobních zkušeností, kterou jsem dal dohromady na základě krátkého googlení.
V tomhle nejsme ve sporu, psal jsem, že na složitější věci si člověk udělá gramatiku… Ale to neznamená, že by regexpy byly na nic – na spoustu věcí se skvěle hodí.
V tomhle nejsme ve sporu, psal jsem, že na složitější věci si člověk udělá gramatiku… Ale to neznamená, že by regexpy byly na nic – na spoustu věcí se skvěle hodí.Tahle odpověď nebyla pro tebe ;) O tomhle už jsme se bavili (dával jsem tenkrát příklad, že na jednoduché věci radši používám
.split()
a indexování polí, než regexpy). Takže v podstatě souhlasím a skutečně nejsme ve sporu.
dával jsem tenkrát příklad, že na jednoduché věci radši používám .split() a indexování polí, než regexpyJaký smysl má srovnávat nástroje postavené nad regexy a
split()
postavený nad konstantními řetězci?
dával jsem tenkrát příkladTím jsem chtěl připomenout tu (imho vyčerpávající) diskuzi, ne argumentovat v téhle.
OK, ale keby si si nakreslil diagram obsahujúci všetky možnosti emailovej adresy, tak by zrovna triviálny nebol.No, jenže takhle je to skoro se vším. Prakticky pokaždé, když někdo použije regexp, tak to má nějakou mouchu, která ti prostě nedojde (částečně kvůli nepřehlednosti), v 99% to funguje dobře a pak najednou v 1% ti spadne na nohu kovadlina z čistého nebe. Ne že by se to nemohlo stát jinde, ale tam většinou není problém to bezbolestně opravit.
Otázkou je tiež, aký výkon pársovania pri tomto štýle zápisu to dokáže dosiahnuť.Klidně ti to může vygenerovat parser v C, který si pak zkompiluješ do nativního kódu.
čo je lepšie Java, alebo Python?Pak by jsme museli definovat význam slova lepší a bylo by to celé nudné a zdlouhavé.
Prakticky pokaždé, když někdo použije regexp, tak to má nějakou mouchuPrakticky pokaždé, když někdo napíše kus kódu, má to nějakou mouchu. Nelze soudit regex (nástroj) podle kontroly mailových adres (častého leč nepříliš užitečného užití) nebo podobných nesmyslů. Podle mě je zkopírovaný regex z netu asi stejně užitečný nebo nebezpečný jako zkopírovaný kód z netu.
Podle mě je zkopírovaný regex z netu asi stejně užitečný nebo nebezpečný jako zkopírovaný kód z netu.Podle mě ne. Pokud je to nepochopený kód z netu, tak ano, ale většinou platí, že kód v programovacím jazyce je podstatně předvídatelnější a přehlednější, než regexp.
Tudíž snažit se s jejich pomocí parsovat html nemůže fungovat, leda bych se mohl spolehnout na nějaké šikovné, ale hlavně neměnné formátování.Ve většině případků, které jsem viděl se lidi snaží vytáhnout jen jeden tag, například
<title>
.
Driv jsem delaval s HTML to, co popisuje Bystroushaak, pres regexpy, dneska bych to ale delal jedine pres BeautifulSoup.Dík za tip.
Driv jsem delaval s HTML to, co popisuje Bystroushaak, pres regexpy, dneska bych to ale delal jedine pres BeautifulSoup.S tím souhlasím, pokud se z toho časem nevyklube spíše úloha v té oblasti, kterou jsem popisoval já.
/html/head/title
PS: zatimco klon RE v Lispu je vice-mene mrtvej a malo kdo ho zna.Co tam používají místo toho?
Tohle moc nepomůže. Co jsem se s odporem k regexpům setkal, tak to je hlavně o nepochopení principu činnosti. Občas pomůže vysvětlení základů stavových automatů a názorná ukázka, jak ten regexp vlastně funguje jako FSM.Nevím čemu by to mělo pomáhat. Já principu činnosti rozumím a asi by mi ani nedělalo problém napsat si jejich interpretr. Jen to prostě vůbec nepovažuji za správný způsob řešení složitých problémů. Přitom platí to co jsem psal - složitost není určována pocitem, ale implementací korektního parseru gramatiky (třeba podle RFC), což je v regexpech většinou k zblití. Viz ten příklad s emailovou adresou.
Tohle moc nepomůže. Co jsem se s odporem k regexpům setkal, tak to je hlavně o nepochopení principu činnosti. Občas pomůže vysvětlení základů stavových automatů a názorná ukázka, jak ten regexp vlastně funguje jako FSM.Jenže přesně na tyhle věci (FSM) regexp právě moc dobrý není. Zájemcům o FSM doporučuji Ragel.
Myslim, ze zakladni problem je v tom, ze regexpy jsou retezce, tj. ze vsechno je znak textu, pokud nejde o vyjimku, tj. operator, a ty je vetsinou treba nejak uvozovat.Souhlasim, souvisejici problem je ten, ze whitespace je chapan take jako matchovany znak a ne jako whitespace v gramatice regularniho vyrazu, v dusledku toho jsou regularni vyrazy typicky necitelne chrchle. Druhy problem vidim v chybejici 'abstrakci a aplikaci', tedy nemoznosti snadno pojmenovat a odkazovat se na pomocne parametrizovane regularni vyrazy a ty pouzit pro skladani finalniho vyrazu. Myslim ze uz jenom techto par uprav by citelnost regularnich vyrazu podstatne zlepsilo.
slovo, identifikatorProblem je v tom, ze prakticky kazdy jazyk ma lehce jinou syntax pro identifikatory, takze univerzalni syntax pro ne neexistuje. Podobne taky pro cislo - ma zahrnovat unarni minus? unarni plus? desetinnou tecku? carku? tecku/carku podle locale? oddelovace tisicu podle locale? To vse zavisi na kontextu, ve kterem to hledam.
Ale jinak se mi libi pristup, ktery prosazuje Augeas (a je dnes myslim dost moderni) - pokud mozno vsechen text nejdriv naparsovat do stromove strukturyTo je ale pristup, ktery s problematikou regularnich vyrazu souvisi jen velmi okrajove.
Souhlasim, souvisejici problem je ten, ze whitespace je chapan take jako matchovany znak a ne jako whitespace v gramatice regularniho vyrazu, v dusledku toho jsou regularni vyrazy typicky necitelne chrchle.To je ale problém toho, kdo to takto používá, minimálně pythoní implementace whitespace umí.
Druhy problem vidim v chybejici 'abstrakci a aplikaci', tedy nemoznosti snadno pojmenovat a odkazovat se na pomocne parametrizovane regularni vyrazy a ty pouzit pro skladani finalniho vyrazu.Nad tím už jsem taky párkrát přemýšlel a na druhou stranu nevidím úplně důvod, proč bych si nemohl v pythonu ty regexy poskládat. Navíc jsem to viděl jako dílčí řešení v nějakém generátoru parserů.
Navic, ja nejsem konceptualne proti regularnim vyrazum (jazykum), ale proti jejich zpusobu zapisu, ktery je neprehledny.A co
re.VERBOSE
v Pythonu?
Občas pomůže vysvětlení základů stavových automatů a názorná ukázka, jak ten regexp vlastně funguje jako FSM.Pomoci FSM jde vysvetlit cokoliv, ale nevim, jak moc to pomuze k pochopeni regularnich vyrazu. ;-]
pochopil jsem tvuj vyrok tak, ze jsou regexpy naprd a jejich jedina vyhoda je, ze jsou kratkeSprávně.
Je teda fakt, ze to slovo zdanlive v te prvni casti nedava moc smysl... nebo to byla cele ironie?Co ti na tom nedává smysl?
cokoliv zdánlivě jednoduchého, jako je emailová adresaViděl jsem desítky případů, kdy se lidi pouštěli přesně do toho, co popisuji, pomocí regexpů, protože si mysleli, že je to lehké. Ve skutečnosti to lehké není, proto jsem psal "zdánlivě lehké".
Jak to tedy parsovat jinak, nez pres regexp?Co třeba dočíst zbytek diskuze?
Já v tom tedy vidím zelenou. A každopádně je to mnohem lepší než třeba žluté písmo na bílém pozadí (viděl jsem v jednom programu, nebo spíš neviděl.
Jedno z pravidel filosofie Pythonu je, že jedna věc se nemá dělat různými způsoby.To má být vtip?
Jedno z pravidel filosofie Pythonu je, že jedna věc se nemá dělat různými způsoby.
There should be one-- and preferably only one --obvious way to do it.První mi stále připadá jako vtip, o druhém jsem ochotný se bavit. Ale jeden příklad za všechny, když chci aby objekt generoval nějakou posloupnost nebo iteroval přes nějaká data, můžu ho udělat jako třídu nebo jako generátorovou funkci. Mám za to, že se obojí prezentuje jako obvious way, takže si nejsem jistý, zda si pythonisti tak trochu nelžou do kapsy.
Ale jeden příklad za všechny, když chci aby objekt generoval nějakou posloupnost nebo iteroval přes nějaká data, můžu ho udělat jako třídu nebo jako generátorovou funkci.Pokud tomu v konkrétním případě něco nebrání, na tohle je IMHO právě určený generátor. Třída může dělat totéž, ale obvykle tato cesta vede na boilerplate kód, ve kterém se ztratí jednoduchá myšlenka.
Psát iterátor má smysl jen když potřebuju něco co generátor neumí (třeba držet více stavových informací než co protlačím z yieldu)Tady se zjevně neshodneme. Já osobně povětšinou spíše zastávám better explicit than implicit, pokud to není vyloženě hezky napsatelné jako generátorová funkce.
A co může být více "obvious" než ušetřit si práci?Více obvious než ušetřit si práci se psaním může být ušetřit si práci se čtením a vyznáním se v tom. Tady asi zase budu ten špatný pro všechny, protože pro frantu nejsem dost javista, pro vás nejsem dost pythonista a pro další nejsem dost perlista.
že třaba operace se soubory nebo přístup k regulárním výrazům se mají dělat přes knihovní funkce
Ono to, že se ti v programu magicky objeví proměnné $0, $1, $2 … a v nich máš skupiny z regulárního výrazu, to trochu prasárna je, ale na druhou stranu to umožňuje psát dost elegantně a úsporně – navíc zrovna tohle je věc, kterou se naučíš celkem snadno a je to takový standard.
Jinak souhlas, když se všechno dělá přes metody/funkce, tak je to srozumitelnější a je v tom větší pořádek. Tohle se mi právě líbí na Javě – všechno je metoda, třída nebo rozhraní, všude se proklikáš na JavaDoc resp. zdroják dané metody… a ten jazyk samotný je jednoduchý.
Na druhou stranu skript na pár řádků radši napíšu v Perlu.
no ono hlavne v jave ked chce clovek urobit "jednoduchu" operaciu ako otvorit subor pre citanie tak sa upise cez vytvaranie niekolkych objektov
Objekty tam sice jsou, ale není to žádná tragédie:
try (BufferedReader vstup = new BufferedReader(new InputStreamReader(new FileInputStream("/etc/passwd")))) { for (String řádek = vstup.readLine(); řádek != null; řádek = vstup.readLine()) { System.out.println("PASSWD: " + řádek); } }
Na počet řádků to není o moc horší než ten Perl.
Případně, pokud to potřebuješ častěji, není problém to zabalit do vlastní třídy a volat to takhle jednoduše:
try (ČtečSouboru vstup = new ČtečSouboru("/etc/passwd")) { for (String řádek : vstup) { System.out.println("Passwd: " + řádek); } }
Ano, je na tom vidět, že složitější věci se skládají z jednodušších a že od implementačních detailů můžeš abstrahovat a pracovat na vyšší úrovni – tohle Java dobře podporuje. A hezké na tom je, že se to řeší pomocí standardních prostředků (rozhraní, třídy, metody…) a ne nějakých speciálních jazykových konstrukcí – takže si takovou knihovnu může napsat kdokoli, ne jen autor jazyka/platformy. A do všeho je dobře vidět, minimum magie a šamanismu
Ano, je na tom vidět, že složitější věci se skládají z jednodušších a že od implementačních detailů můžeš abstrahovat a pracovat na vyšší úrovni – tohle Java dobře podporuje.Stejně jako řada dalších OOP jazyků... Ale abych byl fér, tak ten kód výše není žádná vada jazyka, spíš jen IMHO ne moc šikovný návrh knihovny...
A do všeho je dobře vidět, minimum magie a šamanismuWat? Myslíš jako např. do správy paměti, struktury objektu, způsobu volání metod apod.?
A do všeho je dobře vidět, minimum magie a šamanismuVynutit minimum magie a šamanismu na straně uživatele je možné právě jen když do ničeho dobře nevidí.
Ale abych byl fér, tak ten kód výše není žádná vada jazyka, spíš jen IMHO ne moc šikovný návrh knihovny...
To bude nejspíš tím, že standardní knihovna v Javě nevzniká, jako když pejsek s kočičkou vařili dort. Nejde tam vrazit všechno, co se někomu líbí. Od toho jsou další knihovny/frameworky, které se běžně používají.
Ostatně když si čtu o Pythonu, tak hodně těch zajímavých věcí taky není ve standardní knihovně a člověk by si kvůli tomu musel doinstalovat nějaké obskurní rozšíření od někoho třetího.
Wat? Myslíš jako např. do správy paměti, struktury objektu, způsobu volání metod apod.?
Tím myslím, že když si v IDE klikneš na ČtečSouboru
nebo si u něj zobrazíš kontextovou nabídku, tak vidíš kromě zdrojáku, že implementuje rozhraní AutoCloseable
a Iterable<String>
, takže ho můžeš bezpečně použít jako zdroj v try
bloku a sám se nakonec zavře, nebo že přes něj můžeš iterovat ve for
cyklu.
Tzn. jazyk jako takový je jednoduchý, je tam minimum jazykových konstrukcí, které se musíš naučit, a všechno ostatní se řeší standardními prostředky (rozhraní/třídy/metody…), u kterých snadno zjistíš, co dělají, ve chvíli, kdy na ten kód narazíš.
Co se týče správy paměti atd. – Java není nízkoúrovňový jazyk jako C, takže programátor od těchto věcí normálně abstrahuje, ale pokud tě to zajímá, tak si přečti specifikaci a zdrojáky JVM. Nicméně třeba struktura objektu v paměti je věc, která by aplikačního programátora zajímat neměla – ten má řešit obchodní logiku aplikace a tyhle technické detaily nechat na nižších úrovních a jejích programátorech.
Tím myslím, že když si v IDE klikneš naV tom ale Java opět není nijak výjimečná, tohle je běžné pro celou tuhle skupinu jazyků (ie. OOP staticky typované kompilované jazyky). To, že v Perlu, Pythonu nebo JS tohle obvyklé není, je dané tím, že to jsou dynamicky typovaná* skriptovátka... *) Ten pojem není ani v jednom případě úplně korektní, ale snad víš, co mám na mysli.ČtečSouboru
nebo si u něj zobrazíš kontextovou nabídku, tak vidíš kromě zdrojáku, že implementuje rozhraníAutoCloseable
aIterable<String>
, takže ho můžeš bezpečně použít jako zdroj vtry
bloku a sám se nakonec zavře, nebo že přes něj můžeš iterovat vefor
cyklu.
Nicméně třeba struktura objektu v paměti je věc, která by aplikačního programátora zajímat nemělaTo není pravda. Vědět, kolik paměti objekt zabere nebo jaký overhead má volání jeho metod, je věc, která se občas programátorovi hodí, bez ohledu na to, jak moc se JAvisti snaží přesvědčit svět, že je to jedno a že by lidi upgrade museli dřív nebo později provést tak jako tak, tak proč čekat 2 roky a nenakoupit další RAM rovnou...
Možná tě to překvapí, ale výkonnostní optimalizace nebo jak psát úsporně, se řeší i v Javě. Ale tam jde spíš o to, kolik a jakých objektů (třeba v proměnných dané třídy) máš a ne jakou mají fyzickou strukturu v paměti, jak jsou uspořádané.
Možná tě to překvapí, ale výkonnostní optimalizace nebo jak psát úsporně, se řeší i v Javě.Takto konstruované věty mi značně připomínají poměřování penisů.
Stejně jako řada dalších OOP jazyků... Ale abych byl fér, tak ten kód výše není žádná vada jazyka, spíš jen IMHO ne moc šikovný návrh knihovny...Java je plna uletu, ale toto je zrovna cast, ktera je navrzena dobre. Smysl tech objektu ti uz byl vysvetlen.. Logika je podobne jako v pripade rour v unixech, mas jednu komponentu, ktere dela jednu vec a dela ji poradne. Ale jdou s tim velice elegantne delat dalsi kousky. Obvykle jednotlive metody pracuji s obecnym InputStreamem a je jedno, jestli to mas jakou sobour, TCP/IP spojeni nebo pole bytu v pameti, coz hodne dulezita vlastnost pro testovani. Dal muzes treba pridat objekt GzipInputStream nebo CihperInputStream a hned naprosto transparentne pracovat s komprimovanymi nebo sifrovanymi daty.
Ale jdou s tim velice elegantne delat dalsi kousky. Obvykle jednotlive metody pracuji s obecnym InputStreamem a je jedno, jestli to mas jakou sobour, TCP/IP spojeni nebo pole bytu v pameti, coz hodne dulezita vlastnost pro testovani (...)Jako by tohle nebylo i všude jinde. Viz třeba QIODevice v Qt atd. atd...
5% případů, kdy to potřebuješ, se to bude hoditVazne je to 5%? V pripade, ze chces testovat, jestli ti funguji funkce pro IO spravne, je oddeleni od fyzickeho souboru naprosto nutna vlastnost, ergo je to API navrzene dobre.
Na otevření souboru je potřeba vytvořit tři objekty. Komu se to nelíbí, může si vytvořit čtvrtý a ty tři do něj zabalit. Javovská filosofie v kostceLOL.
To je ale potřeba všude (ať už třídy nebo třeba funkce):
Tahle komplexita tam prostě je vždycky, nelze se jí vyhnout. Jde jen o to, jestli si ji zabalíš do nějaké jedné funkce/třídy – tím získáš pohodlí a kratší zápis a zase ztratíš flexibilitu (bude to jednoúčelové).
Je jen otázka, jestli tahle abstrakce má být přímo ve standardní knihovně (nebo pro ni dokonce má existovat nějaká speciální jazyková konstrukce) nebo jestli se implementuje v jiné knihovně. Není to věc jazyka.
Někdy potřebuješ číst ze souboru, jindy zdroj z CLASSPATH, jindy ze sítě… někdy čteš text ve standardním kódování své platformy, jindy v jiném (protože jsi ten soubor třeba stáhl ze sítě z jiného systému)… někdy potřebuješ číst po řádcích, jindy po slovech, regulárních výrazech, po blocích s fixní délkou nebo podle nějakých jiných oddělovačů… někdy budeš mít ty oddělovače už na úrovni bajtů a na text budeš převádět až ty jednotlivé části…
Java je v tomhle mnohem věrnější unixové filosofii – jeden nástroj dělá jednu věc, dělá ji dobře a nástroje můžeš skládat. A nic ti nebrání si udělat shellovský skript (třídu/metodu), který zabalí víc nástrojů dohromady, a můžeš je tak pohodlně zavolat jedním příkazem.
Tahle komplexita tam prostě je vždycky, nelze se jí vyhnout.S tím určitě souhlasím, ale o to mi nešlo, šlo mi o ty objekty jako takový. Jednak se mi moc nelíbí kód, kde je X-krát
new Foo
, ale hlavně objekty v Javě mají docela slušnou řežii, každý má nějaké meta-informace, metody se volají přes vtable nebo nějaký takový mechanismus, musí se o něj starat GC, atd. Bohužel řada i dobrých programátorů v Javě na tohle zcela zvysoka kašle a balí objekty do objektů ad infinitum...
hlavně objekty v Javě mají docela slušnou řežii, každý má nějaké meta-informace, metody se volají přes vtable nebo nějaký takový mechanismus, musí se o něj starat GCProc lzes? ;-] Vtip je v tom, ze prekladac dela "Escape analysis" (alespon od verze 7 AFAIK) a pokud uzna za vhodne, muze pripadne prevest alokaci na zasobnik, prime volani metod, atd.
Bohužel řada i dobrých programátorů v Javě na tohle zcela zvysoka kašle a balí objekty do objektů ad infinitumCo z toho, kdyz si s tim prekladac udela, co uzna za vhodne?
objekty v Javě mají docela slušnou řežii, každý má nějaké meta-informace, metody se volají přes vtable nebo nějaký takový mechanismus, musí se o něj starat GC, atd.To mi něco připomnělo :)
$ find -name '*.java' | grep -o '[^/]*\.java' | sort ArrayListFactory.java GenericFactory.java HashMapFactory.java KeyExtractor.java LineSourceTokenizerFactory.java LineSourceTokenizer.java LineSourceTokenizerNGTest.java LoadableMapImpl.java LoadableMap.java LoadException.java LoadRuntimeException.java RegexKeyExtractor.java SourceTokenizerFactory.java SourceTokenizer.java SqlLoadableMap.java SqlLoadableMapNGTest.java StringCopyTranslator.java StringValueAppenderFactory.java StringValueAppender.java Translator.java ValueAppenderFactory.java ValueAppender.java:-P
with open('/etc/passwd') as f: for line in f: print('passwd:', line.strip())
A co s tím? Java tam má navíc:
do_something([line.split() for line in open("/etc/passwd")])Versus:
with open("/etc/passwd") as stream: do_something([line.split(":") for line in stream])To, že každé blbosti musíš dát jméno, bylo vždycky doménou céčka, kde podle starších norem navíc to jméno muselo být vytvořeno na začátku bloku. Ale tady musím v Pythonu dávat jméno file objectu, který mě vlastně vůbec nezajímá a je tam jenom od toho, aby mi z něj vypadly řádky. Ale nebýt toho
with
, kdybych to musel dělat pomocí finally
, to bych to asi psal rovnou v C pomocí goto
.
U pythonu je zase legrační, jak se nemůžeš spolehnout na vyčištění objektu při jeho dropnutíJak to? Já žiju dlouhá léta v domnění, že to jde. Dokonce to čas od času používám v interaktivních shellech.
with
existuje a musíš ho implementovat pomocí __exit__
a nikoliv __del__
. Jedna ze základních vlastností pythonu pokud vím je, že negarantuje zavolání __del__
ani jiné speciální metody při ztrátě poslední reference.
Moc rád bych se v tomto případě nechal vyvést z omylu a dozvěděl se, že současné verze pythonu garantují úklid objektu při ztrátě poslední reference. Je jen málo věcí týkajících se pythonu, které by mě potěšily víc. Teď mě napadá, že jse blbec, že jsem nenapsal RFE rovnou do jejich bugtrackeru.
Ale tady musím v Pythonu dávat jméno file objectu, který mě vlastně vůbec nezajímá a je tam jenom od toho, aby mi z něj vypadly řádky.Souhlasím, dokonalé to není.
Nechci tady dělat advokáta, ale je nutné vzít do úvahy dobu vzniku a tehdejší situaci na "trhu" programovacích jazyků. Perl přinesl převratný přístup v práci s textem a snadném a rychlém prototypování. Na rozdíl od rozšířených urban myths v něm lze psát přehledně a čitelně, štábní kultura je na programátorovi.
Perl má už asi svoje období slávy za sebou, ale pořád patří z trojice Perl, Python, Ruby k jednoznačně nejúspěšnějším. Python(3) i Ruby jsou celkově na ústupu a nevím co by se muselo stát aby Perl o prvenství připravily.Python(3) i Ruby jsou celkově na ústupuCitation needed
.. ale pořád patří z trojice Perl, Python, Ruby k jednoznačně nejúspěšnějším. Python(3) i Ruby jsou celkově na ústupu a nevím co by se muselo stát aby Perl o prvenství připravily.Pobavilo. V podstatě jediné místo, kde se ještě používá Perl je unixové scriptování, všude jinde to už (naštěstí) vymřelo. Ani tam to ale imho není přílivem nových developerů, ale konzervativností těch starých. Podle TIOBE, PYPL, RedMonku, trendyskills, langindexu i langpop je perl daleko za pythonem a ve 3 z 5 případů i za ruby. Když se podíváme na grafy z githubu, tak je myslím trend docela výstižný. Python je před perlem i co do počtu nabídek na jobs.cz, což už je co říct, vzhledem k tomu že má v ČR asi tak o 10-15 (kritických, unixových) let větší tradici, než python. U nás v práci se na pár místech taky používá, ale většinou jsou to scripty co někdo před 20 lety napsal a od té doby se na ně nešahá. Až se jednou rozbijí (pravděpodobně po smrti stoletého unixáka, který je před 20 lety psal), tak se to nikdo nebude snažit přepisovat, ale prostě to napíše odznova.
U nás v práci se na pár místech taky používá, ale většinou jsou to scripty co někdo před 20 lety napsal a od té doby se na ně nešahá. Až se jednou rozbijí (pravděpodobně po smrti stoletého unixáka, který je před 20 lety psal), tak se to nikdo nebude snažit přepisovat, ale prostě to napíše odznova.
Tohle je víc o stylu než o jazyce – tentýž problém můžeš mít i v Pythonu nebo třeba C++. A na druhou stranu: v Perlu se dá psát slušně, jednoduše, tak aby to kdekdo přečetl.
Tohle je víc o stylu než o jazyce – tentýž problém můžeš mít i v Pythonu nebo třeba C++.Tak dát do jedné věty o prasáckém zdrojáku python a C++, to už chce pořádný koule :D V pythonu jsem se s tím setkal, ale vždy bez vyjímek od programátorů, co přišli z javy/C a tahali si tam s sebou různé idiomy, které python řeší podstatně jednodušeji. Ten nejprasáčtější kód co jsem během dlouhé doby řešil měl hlavní problém v tom, že byl psaný moc lowlevel. Autor byl očividně zvyklý na C/C++ a tak si definoval vlastní struktury, se kterými pracoval pomocí co nejvíc lowlevel řešení. Když jsem to po něm přepisoval, tak se to smrsklo na 1/10 kódu, protože jsem použil tady slovník, támhle trochu funkcionální magie a z programu skoro nic nezbylo.
tady slovník
Místo struktury/třídy? Takže je tam příliš volná vazba, textové řetězce-klíče místo polí. Tohle jsou právě ty prasárny, které se špatně udržují – na jednom místě něco změníš a jinde se to rozpadne, ale není to na první pohled vidět.
támhle trochu funkcionální magie
to se bude taky moc dobře číst…
támhle trochu funkcionální magie
Programy – pokud mají být udržovatelné – tak by té magie měly obsahovat co nejméně, měly by být na první pohled čitelné, přímočaré.
Jestli tím byl myšlen princip map/reduce, tak budiž (a ten se netýká jen funkcionálních jazyků).
Programy – pokud mají být udržovatelné – tak by té magie měly obsahovat co nejméně, měly by být na první pohled čitelné, přímočaré.Magie neznamená nutně "hacků". Je to prostě o featurách pythonu, které člověku umí ušetřit spoustu práce. Samotný jazyk obsahuje tak vysokoúrovňové koncepty, že si programátor připadá jak v bavlnce, která ho odstiňuje od nutnosti zbytečně pořád vymýšlet vlastní idiomy a struktury. Umím si představit, že v nějakém lispu to může být ještě pohodlnější.
Je to prostě o featurách pythonu, které člověku umí ušetřit spoustu práce.
Totéž platí u toho Perlu nebo C++. Potíž je v tom, když ten jazyk těch featur má moc a každý programátor ovládá jinou podmnožinu.
Totéž platí u toho Perlu nebo C++. Potíž je v tom, když ten jazyk těch featur má moc a každý programátor ovládá jinou podmnožinu.S tím právě souvisí to, že tyhle jazyky na rozdíl od pythonu přímo podporují filosofii, že k jednomu výsledku vede mnoho cest. Pak je v tom taková roztříštěnost, kdežto v pythonu když už se něco takového používá, tak je to skutečně komunitní standard. Samozřejmě že i tady by se našly vyjímky, ale obecně z toho mám lepší pocit.
textové řetězce-klíče místo políJako klíč se dá použít cokoliv, co má definováno
__hash__
imho.
Tohle jsou právě ty prasárny, které se špatně udržují – na jednom místě něco změníš a jinde se to rozpadne, ale není to na první pohled vidět.Tohle platí ve velkých programech, kde je rozumnější samozřejmě předávat třídu, jenž strukturu dat popisuje poněkud očividněji. Pokud ale předáváš data, která už sama o sobě jsou key:val charakteru (s unikátním keyem), tak nemá smysl si na to definovat vlastní datové typy, ani to cpát skrz pole.
to se bude taky moc dobře číst…To jsem rád, že se shodneme. Podle me je použití
filter()
/map()
100x čitelnější, než když se to rozepisuje do for smyček, které nedělají nic jiného, než jen nějak upraví procházená data. To že se to někomu zdá nečitelné je dané většinou jen tím, že s podobným konceptem přichází do styku poprvé.
Jako klíč se dá použít cokoliv, co má definováno __hash__ imho.
To by mělo smysl třeba v Javě nebo jiném jazyce s generiky, kde ti kompilátor zkontroluje, že do klíčů necpeš nesmysly – měl bys mapu, kde je klíčem enum (nebo instance jiné třídy) a nešlo by tam cpát nesmysly, neexistující klíče nebo překlepy.
Pokud ale předáváš data, která už sama o sobě jsou key:val charakteru (s unikátním keyem), tak nemá smysl si na to definovat vlastní datové typy
A ta množina klíčů je předem neznámá? Pokud ano a pracuji s tím všude jen obecně, aniž bych jednotlivým klíčům přikládal nějaký zvláštní význam, tak nemám nic proti, je to prostě normální mapa. Ale pokud jsou třeba na druhém konci programu zadrátované určité klíče a ty vytahuji z té mapy, tak už to dost možná bude chyba návrhu. Když už existují nějaké předem známé klíče s určitým významem, tak je lepší tomu dát řád – udělat z toho třídu s atributy, strukturu, nebo třeba enum, který použiji jako klíče mapy (v jazyce, který vynutí typovou kontrolu). A ne že v jedné části programu použiji klíč "xyz" a v jiné části si budu číst "xyz" a budu doufat, že se trefím a že tyhle textové řetězce na sebe budou pasovat.
Když máš nějaký framework, který definuje obecné rozhraní a jednotlivé implementace se mají nějak parametrizovat, tak se někdy používají URI/URN/URL jako klíče (tzn. globálně jedinečný identifikátor) a dávají se věci do mapy, je to hodně volná vazba. Ale to jsou spíš výjimečné případy – je to daň za unioverzálnost, abstrakci a jednoduchost rozhraní. Díky té globální unikátnosti v tom nebude úplný bordel, ale správné hodnoty klíčů si musí programátoři ohlídat sami (třeba přes nějakou třídu s konstantami, dobrou dokumentaci…). Ale to bych použil, jen když to nejde jinak – když můžeš mít typovou kontrolu, tak je to lepší.
ani to cpát skrz pole.
Polem bylo myšleno field, ne array. Tzn. atribut třídy/instance.
namedtuplePravdu díš, v práci je používáme docela často. Mají ale jednu potenciální vadu - jsou immutable.
Celkom nepríjemná vlastnosť, ale na nejaké menšie úpravy sa dá použiť _replace
enumerate()
/sum()
, místo aby to člověk psal ručně.
TIOBE Index for Python Vrchol 2011, pokles ze 7% na necela 3% (sestupny trend 2011 az 2014)
TIOBE Index for Ruby Vrchol 2009, pokles ze 4% na cca 1,5% (sestupny trend 2009 az 2014)
TIOBE Index for Perl Vrchol 2005, pokles z 11% na cca 1,5% (sestupny trend 2005 az 2014)
Popularita JS je zajimava a zrejme souvisi s podporou velkych firem, porad lepsimi interprety i JIT kompilatory a rozsirenim i mimo webove klienty (jako Node.js a silenstvi kolem). Holt kvalita navrhu jazyka ho sama o sobe neprosadi.
Perl je sice evidentne na ustupu, ale tech skoro 11% z 2005 ty dva zatim nemeli.Tak určitě se nebudu hádat o tom, že perl byl populárnější než je python. V současnosti ale chcípá někde více/méně na okraji zájmu, částečně (prý) vlastní vinou (perl 6?).
Popularita JS je zajimava a zrejme souvisi s podporou velkych firem, porad lepsimi interprety i JIT kompilatory a rozsirenim i mimo webove klienty (jako Node.js a silenstvi kolem). Holt kvalita navrhu jazyka ho sama o sobe neprosadi.Tohle je právě docela zarážející, protože javascript sám o sobě je poměrně hodně dementní. Wat už viděl asi každý. Na druhou stranu, co taky čekat od jazyka napsaného za 10 dní.
Perl 6 nemá s Perlem 5 nic společného. Jestli se chceš pobavit, tak naposledy se na p5p probíral návrh na zavedení unicodových operátorů (≠
jako !=
).
JavaScript je o tom, že máte hromadu programátorů webových stránek, z kterých si výrobci toolkitů chtějí udělat zákazníky. Podívejte se, co se stalo Qt. GTK+ tam směřuje taky. XUL a všechny „web OS“ (Chrome OS, Firefox OS, Tizen) tam už jsou. Zcela paradoxně dnes nejžádanější platformy Android a iOS nejsou javascriptové. Proto ten hon na JavaScript. Web není moderní, moderní jsou mobilní aplikace, kde ale vzít vývojáře? Proto je v poslední době snaha všechno zjednodušit a přiblížit průměrnému webaři. Je snaha z programování udělat komoditu, nikoliv výlučnou doménu přeplacených geeků. Kvalita už nikoho nezajímá. Nahradit ji má kvantita. (To samé platí o nasazování serverových částí, proto ten šrumec kolem OpenStacku a Dockeru.)
Javascript nie je až tak zlý. No síce vlastne keď tak rozmýšľam, že už 5 dní vkuse robím drag & drop sortovanie tak no ehm ... ale to je blbou knižnicou ktorá sa nejako nevie vysporiadať s CSS (premýšľam či by som to nemal skôr keby som si to písal sám namiesto blbého jquery nested sortable). Teda no knižnice sú úplne naprd (väčšinou) ale zato samotný jazyk je no síce zlé navrhnutý ale niektoré veci sa vydarili napr.
['10','10','10','10','10'].map(parseInt) [ 10, NaN, 2, 3, 4 ]
The ratings are calculated by counting hits of the most popular search engines.Statistiky GitHub jsou mnohonasobne vice vypovidajici, nebot sleduji realny kod.
To mě opravdu pobavilo, jak tady vlastní subjektivní dojmy vydáváte za standard.Myslíš ty subjektivní dojmy podložené 6 odkazy na weby zabývající se popularitou programovacích jazyků?
"U nás v práci" bychom bez Perlu ani nezbuildovali projekt, protože tam máme dost užitečných scriptů, které efektivně automatizují veškeré generování textových výstupů včetně určité části zdrojového kódu v C. Pochopitelně jsou aktivně vyvíjené - "u nás v práci" na to máme celý tým a tak nějak jsem si nevšiml, že by jim bylo 100 let - jsou většinou daleko mladší než já. "U nás v práci" mám kromě práce na kódu vlastního projektu na starosti ještě průběžný vývoj toolu v Perlu, kde se to regexpy jen hemží... "U nás v práci" je Python dobrý leda tak k psaní testovacích sekvencí pro simulátorCo to vlastně děláš? Psal jsem jak to chodí u nás v práci a ty mi na základě toho jak to chodí u vás dokazuješ, že to tak není? Nikde jsem netvrdil, že perl nikdo nepoužívá, ani že to stejně jako u nás funguje všude. Jediný výraz kde jsem psal něco o tom jak se perl používá bylo tvrzení, že se využívá jen k scriptování na unixu, což jsi částečně potvrdil. Takže tu poslední ani první větu fakt nechápu.![]()
Já v něm, mimochodem, píšu objektově :) Původně jsem za to člověka, po kterém jsem to převzal proklínal, ale ono to v Perlu jde docela dobře.Tohle myslím vypovídá o perlu (a jeho typických uživatelích) víc, než tisíc slov.
Co se týče Pythonu, ten je tady brán jako nástroj k rychlému prasení.To je hezké, zrovna mezi perlisty ;).
o nemohl navrhnout třeba nějakou interpretovanou podmnožinu CAWK? Pike?
if ($i) { $i++ }; $i++ if $i; $i++ unless $i == 0;Perl je zaroven objektovy, funkcionalni i proceduralni jazyk. Ccko nema map/reduce, neumoznuje ani spustit virtualni masinu unitr virtualni masiny (eval), nema paralelismus, nema reflexi a samozrejme nema ani dedicnost.
Jak predtim mohl vypadat distribuovany vyvoj software, kdy do mailove konference asi bylo zvykem posilat cely upraveny soubor, si radsi nepredstavuju.Ale prd. Utilita diff je tu od 70.let, patch to jen zefektivnil.
diff
byl, ale patch
chyběl
Dnes to tak nevypadá, ale skutečně to předtím nikoho nenapadlo a byla to revoluce. Alespoň to píše ESR v The Art of Unix Programming
diff byl, ale patch chybělPouzival se diff a ed.
diff -e old_file new_file > diff_fileA potom ho aplikovat:
(cat diff_file && echo w) | ed - old_fileLarry prisel s lepsim resenim, ktere pouzivalo unifikovany format, napsane v C a ktere se pozdeji prosadilo jako standard, hlavne diky GNU. Davam mu za to body, ale rozhodne to nebylo tak, ze by lide museli posilat cele soubory a mergovat neco rucne, zejmena kdyz navic existovali skripty, ktere se chovali podobne jako patch. O tom svedci fakt, ze diff tu byl o trinact let drive nez patch, takze to asi nebyl az takovy problem.
Larry prisel s lepsim resenim, ktere pouzivalo unifikovany formatNikde se to moc nepíše, ale myslel jsem si to z nějakých náznaků, že aplikoval patch i na změněný soubor.
O tom svedci fakt, ze diff tu byl o trinact let drive nez patch, takze to asi nebyl az takovy problem.Zase na druhou stranu pokud používali
diff -e
a následně aplikovali pomocí ed
, nemohli dost dobře aplikovat na změněný soubor.
že aplikoval patch i na změněný soubor ... nemohli dost dobře aplikovat na změněný soubor.To je pravda. Fungovalo to rozumne jen s context diff, ktery v 1984 nebyl standard a s RCS/SCCS verzovanim, takze nakonec nejednodussi bylo stale poslat ed script. Pokud na danem radku kontext nedpovidal, pozice se posouvala a kontext opet porovnaval; reseni chytre, nikoliv nove, obdobne to slo delat [i interaktivne] v Emacs. IMHO, jestli neco bylo nove, soude podle vyjadreni jednoho byvaleho Unix programatora Stallmanovi generace, byla to moznost reverse, ktera umoznovala delat snadno regresni testy.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.