Autor | Zpráva | ||
---|---|---|---|
obi Profil |
#1 · Zasláno: 30. 6. 2010, 10:32:36
Ahoj,
narazil jsem v regulárních výrazech na docela zásadní problém, jde o tohle: Chci dejme tomu najít v textu řetězec začínající slovem "START", následovaný čímkoli kromě slova "ahoj" a končící slovem "END". <?php $text = "nějaký začátek START blabla ahoj ble END a nějaký konec"; preg_match_all("#START .*(?!ahoj) END#U", $text, $matches); print_r($matches); ?> Prosím o radu a předem děkuji :-) |
||
nightfish Profil |
#2 · Zasláno: 30. 6. 2010, 11:08:58
Napadá mě jenom udělat to "dvouprůchodově".
<?php $text = "nějaký začátek START blabla ahoj ble END a nějaký konecSTART neco neco END neco"; preg_match_all("#START(.*)END#U", $text, $matches, PREG_SET_ORDER); foreach ($matches as $v) { if (!preg_match('#ahoj#', $v[1])) { print_r($v); } } Ale třeba přijde někdo s něčím lepším. |
||
Joker Profil |
#3 · Zasláno: 30. 6. 2010, 12:01:10
nightfish:
Když dvouprůchodově, tak v tom druhém už bych použil jen strstr, tam není potřeba regulární výraz. |
||
obi Profil |
#4 · Zasláno: 30. 6. 2010, 12:23:05 · Upravil/a: obi
Bohužel tohle potřebuju kvůli daleko složitějšímu problému a dělat to dvou-průchodově by znamenalo strašné znepřehlednění (pokud by to vůbec v tomhle případě šlo použít)
Musí existovat i jiný způsob, určitě na tak základní věc nemohli tvůrci reg. výrazů zapomenout :-( |
||
obi Profil |
#5 · Zasláno: 30. 6. 2010, 13:04:23
Tak jsem na něco přišel :-)
<?php //tohle už funguje $text = "nějaký začátek START blabla ahoj ble END a nějaký konec"; preg_match_all("#START (?!.*ahoj).* END#U", $text, $matches); print_r($matches); ?> ------ Bohužel ale nastal další problém: <?php //v tomto řetězci nevyhovuje žádná jeho část, přestože 'ahoj' je až za slovem 'END' $text = "nějaký začátek START blabla ble END a nějaký ahoj konec"; preg_match_all("#START (?!.*ahoj).* END#U", $text, $matches); print_r($matches); ?> |
||
Radek9 Profil |
#6 · Zasláno: 30. 6. 2010, 13:07:44
obi:
Mně funguje tohle: $text = "nějaký začátek START blabla ble END a nějaký ahoj konec START blabla blesdgsdg END"; preg_match_all("#START (?!ahoj*).* END#U", $text, $matches); print_r($matches); |
||
obi Profil |
#7 · Zasláno: 30. 6. 2010, 13:12:42 · Upravil/a: obi
Radek9:
> Mně funguje tohle: > > preg_match_all("#START (?!ahoj*).* END#U", $text, $matches); tomuhle odpovídá i řetězec "něco START blabla ahoj ble END něco jiného", právě jsem to zkoušel |
||
Radek9 Profil |
#8 · Zasláno: 30. 6. 2010, 13:13:58
obi:
Pravda, zkusím dál testovat. |
||
AM_ Profil |
#9 · Zasláno: 30. 6. 2010, 13:20:30
Radek9:
proč mezera po START a před END? navíc to znamená: [START] [mezera] [něco jiného než ahojjjjjjjjjjjj...] [jakékoli znaky] [mezera] [END] šel bych spíš tímto směrem: preg_match_all("#START(?!.*?ahoj.*?).*?END#U", $text, $matches); ale problém zřejmě bude např. START blabla END ahoj, protože po START to najde ahoj. Sice až za END, ale nevím, jestli se dá ta lookahead podmínka nějak omezit jen po to END |
||
obi Profil |
#10 · Zasláno: 30. 6. 2010, 13:20:33
tak jsem zase o krok dál
<?php //tohle požadovaný řetězec najde $text = "něco START aa bb END ahoj konec"; preg_match_all("#START (?!.*ahoj.*END).* END#U", $text, $matches); print_r($matches); ?> <?php //ale v tomto řetězci už je problém $text = "něco START aa bb END prostředek ahoj START cc ahoj dd END konec"; preg_match_all("#START (?!.*ahoj.*END).* END#U", $text, $matches); print_r($matches); ?> |
||
nightfish Profil |
#11 · Zasláno: 30. 6. 2010, 13:38:08
Joker:
„Když dvouprůchodově, tak v tom druhém už bych použil jen strstr, tam není potřeba regulární výraz.“ Svatá pravda. (I když pak tedy spíš strpos než strstr.) obi: „Bohužel tohle potřebuju kvůli daleko složitějšímu problému a dělat to dvou-průchodově by znamenalo strašné znepřehlednění (pokud by to vůbec v tomhle případě šlo použít)“ Tak nás netahej za nos a napiš, k čemu to potřebuješ. Řešit tady příliš zjednodušenou variantu nemá smysl. |
||
obi Profil |
#12 · Zasláno: 30. 6. 2010, 13:51:32
nightfish: oki, klidně, i když i tahle zjednodušená varianta by mě zajímala ;-)
Chci si vytvořit SQL parser, který mi z SQL dotazu vytáhne názvy tabulek. Vstup: SELECT *, field1 as muj_sloupec, field2 FROM tabulka_3 z, (SELECT * FROM tabulka_1) x JOIN tabulka_2 y ON x.jmeno=y.id WHERE field3='val1' AND field4=5 Výstup: array( [0] => tabulka_3, [1] => tabulka_1, [2] => tabulka_2 ) |
||
AM_ Profil |
#13 · Zasláno: 30. 6. 2010, 14:08:07
No, pokud ti jde jen o názvy tabulek, tak stačí všechny znaky platné pro název tabulky za FROM ;) ale budeš muset asi rozlišit dva případy, jednak názvy bez apostrofů (menší výčet povolených znaků) a názvy v apostrofech (od prvního apostrofu k dalšímu).
Pokud ale chceš dotaz nějak důkladněji analyzovat, vykašlal bych se na regulární výrazy a napsal si sekvenční syntaktický analyzátor - není to legrace, ale výsledek bude lepší, než přes reguláry, přecejen na syntaktyckou analýzu stavěné moc nejsou... |
||
nightfish Profil |
#14 · Zasláno: 30. 6. 2010, 14:13:48 · Upravil/a: nightfish
Názvy tabulek se mohou vyskytovat jenom na určitých místech - v [#12] je to za FROM a za JOIN. Stejně tak mohou názvy tabulek obsahovat jenom určité znaky.
Přibližně by to mohlo vypadat takto: ~(FROM|JOIN)\s([^\s]+)[\s,]~s // název tabulky uveden napřímo, končí první čárkou nebo bílým znakem ~(FROM|JOIN)\s`(.*)`~sU // název tabulky uzavřen ve zpětných apostrofech Pokud by bylo potřeba s tím kouzlit víc, asi by stálo za to si někde najít/napsat vlastní SQL parser (i když na tohle by stačilo udělat jenom tokenizer). EDIT: jejda, psal jsem tak dlouho, až jsem napsal totéž co AM_ |
||
Nox Profil |
#15 · Zasláno: 30. 6. 2010, 15:29:30
obi teda výslovně neřek, že to smí být jen selecty...
k tomu by přibylo (asi nekompletní seznam) ALTER TABLE [table] INSERT INTO [table] UPDATE [table] LOCK TABLES [table] DROP [table] RENAME TABLE [table] SHOW (FULL) TABLES [table] ... Což by teda nebylo až tak kritický, ale... nightfish: ...navíc: INSERT INTO table1 (header) VALUES ('NEWS FROM BRNO') => table1, BRNO Takže ten parser by fakt byl asi třeba Když jsem hledal jak zajistit, že výraz není v uvozovkách, našel jsem jen nějaký složitý regexp, kde se počítalo zda následují páry uvozovek (a do toho by se muselo ještě přidat escapování) takže asi kopec srandy |
||
obi Profil |
#16 · Zasláno: 30. 6. 2010, 15:32:30
nightfish:
„~(FROM|JOIN)\s([^\s]+)[\s,]~s“ tohle funguje pro jednoduché dotazy, ale např. tabulku 'tabulka_2' bychom tímto stylem v následujícím dotazu hledali těžko: SELECT * FROM (SELECT neco FROM tabulka_1 WHERE id=5), tabulka_2 zkusím teda na netu pohledat něco o tvorbě toho "sekvenčního syntaktického analyzátoru" a o "tokenizeru" (vůbec nevím co to je a jak to má fungovat). |
||
AM_ Profil |
#17 · Zasláno: 30. 6. 2010, 15:59:31
[#16] obi
to je pravda, moc jsem nepromyslel složitější dotazy... no jde o to, že si znak po znaku (resp. token po tokenu) čteš ten příkaz, pamatuješ si aktuální stav (jaký příkaz a kterou jeho část zrovna načítáš) a ukládáš to do nějaké rozumné struktury... |
||
obi Profil |
#18 · Zasláno: 30. 6. 2010, 17:16:24
AM:
„no jde o to, že si znak po znaku (resp. token po tokenu) čteš ten příkaz, pamatuješ si aktuální stav (jaký příkaz a kterou jeho část zrovna načítáš) a ukládáš to do nějaké rozumné struktury...“ To zní složitě :-D Kdybych uměl napsat regulární výraz SELECT cokolivNeobsahujici(FROM) FROM cokolivNeobsahujici(WHERE|ORDER|GROUP|LIMIT) byla by to otázka jednoho regulárního výrazu (pro select) a jednoho cyklu. Takže jsem zase u mojí původní otázky, jak ten regulární výraz 'cokolivNeobsahující(něco)' napsat... |
||
AM_ Profil |
#19 · Zasláno: 30. 6. 2010, 17:46:00
SELECT `FROM`, `ahoj` FROM test asi se té syntaktické analýze opravdu nevyhneš. Ano, je to složité, ale přes reguláry je hotové peklo pokrýt všechny případy.. |
||
obi Profil |
#20 · Zasláno: 30. 6. 2010, 18:07:41
AM:
„no jde o to, že si znak po znaku (resp. token po tokenu) čteš ten příkaz, pamatuješ si aktuální stav (jaký příkaz a kterou jeho část zrovna načítáš) a ukládáš to do nějaké rozumné struktury...“ vůbec si nedokážu představit, jak by takový algoritmus v PHP vypadal... a na netu jsem taky nic nenašel |
||
Časová prodleva: 14 let
|
0