| Autor | Zpráva | ||
|---|---|---|---|
| 4ever Profil |
Asi mě zabijete, že sem zase píšu dotaz na regulární výraz :-/
Moderátor Joker: To je v pořádku, jen to chce trošku uvažovat nad titulkem, takhle bychom tu měli tisíc vláken „regulární výraz“.
Dodatek: Přečetl jsem si to ještě jednou a ještě upravuji titulek, aby víc odpovídal dotazu. Mám tento výraz: $regex = '(?:<p class="cl_odstavec">.*)([Žž]ena.*)(?:\<br\>|\.>)' A potřeboval bych tu vnořenou předlohu upřesnit, aby vrátil větu, ve které se nachází slovo žena, ale aby nezahrnul větu, která ji může předcházet a obsahuje slovo "muž". No spíše, vůbec nezahrnovat předchozí větu. Není jisté jestli tam nějaká věta je nebo není, ale zajímá mě celá věta o ženě, takže před ženou ještě musí být něco jako .*. Jinak je to v kontextu reguláru, který nerozulišuje velikost písmen a používá UTF-8, tak si teď nejsem jistý zda třída [Žž] je nutná. |
||
| Joker Profil |
#2 · Zasláno: 19. 8. 2011, 21:55:11
4ever:
Teď je otázka podle čeho se pozná hranice věty. A nakolik to bude spolehlivé, když spousta lidí si dneska s interpunkcí moc hlavu neláme. |
||
| Tori Profil |
#3 · Zasláno: 19. 8. 2011, 21:59:33
4ever:
Takže když si to rozložíte ( předpokládám, že věta končí tečkou), jdou za sebou tyhle části: <p class="cl_odstavec"> (možná nějaké znaky, které končí tečkou) začátek věty (= znaky, které neobsahují tečku, anebo žádné znaky) // toto chcete slovo "žena" // toto chcete - btw je to vždy v 1.pádu? konec věty (= znaky, které končí tečkou, anebo tečka) // toto taky chcete |
||
| 4ever Profil |
#4 · Zasláno: 19. 8. 2011, 22:24:16 · Upravil/a: 4ever
Joker:
Je to na hledání textu ve článku. Hranice věty je určena tečkou. Tori Edit: vlastně je to správně Jde jen o to určit, co se nachází před ženou a co se tam nenachází a co z toho bude zahrnuto do výsledku. [Žž]ena je vždy v prvním pádu, resp. přesně tento tvar mě zajímá. Jinak já mám jako zakončení ještě možnost <br>, zalomení odstavce, ale to teď nevím proč tam mám, jestli to je nutné. <p class="cl_odstavec"> (možná nějaké znaky, které končí tečkou) začátek věty (= znaky, které neobsahují tečku, anebo žádné znaky) // toto chcete slovo "žena" // toto chcete - ano vždy v 1.pádu. konec věty (= znaky, které končí tečkou, anebo tečka) // toto taky chcete |
||
| 4ever Profil |
#5 · Zasláno: 19. 8. 2011, 23:08:51 · Upravil/a: 4ever
Tak snad by to mohlo být takto:
'(?:<p class="cl_odstavec">.*\.{0,1})(.*[Žž]ena.*)(?:\<br\>|\.>)',
či lépe '(?:<p class="cl_odstavec">.*\.?)(.*[Žž]ena.*)(?:\<br\>|\.>)', Ovšem nejsem si jistý jestli trojí výskyt .* nezpůsobuje značné zpomalení. Zdá se mi to nějaké dost pomalé, ale je to možná tím, že to aplikuju na více souborů. Edit 2: Jenže problém je právě v tom: (.*[Žž]ena.....) že .* vrací i ty slova kde se nachází muž. Takže např. <p class="cl_odstavec">Muž nosí kalhoty. Kdežto žena nosí sukni. Nebo šaty. Vrátí to "Muž nosí kalhoty. Kdežto žena nosí sukni. Nebo šaty." Což je špatně, protože muž mě nezajímá. Takže jak vrátit všechny znaky od tečky, kde se nenachází muž? Edit 3: zatím mám jen toto: '(?:<p class="cl_odstavec">.{0,150}\.?)((?:.*muž.*\.){0,0}[Žž]ena.*)(?:\<br\>|\.>)',
Když to rozložím: 1. Jakékoliv znaky, které se vyskytují nula krát až 150x.
.{0,150}\.?)
Jsou následovány 2. výrazem, kde se nezachycuje muž ?:. Výraz kde je muž (znaky před a za mohou a nemusí být .*) a končí tečkou \., se nesmí vůbec vyskytovat {0,0}.
((?:.*muž.*\.){0,0}[Žž]ena.*)
Tento výraz je však ekvivalentní výrazu, ve kterém bychom řekli, že chci najít pouze větu, která začíná na slovo žena. 3. pokud se pokusím před slovo žena přidat .* tak to automaticky zahrne i tu předlohu, která vylučuje muže. Zkoušel jsem ještě použít funkci or | ale to je to samé. Zatím to vypadá neřešitelně... |
||
| Majkl578 Profil |
#6 · Zasláno: 20. 8. 2011, 01:02:48 · Upravil/a: Majkl578
A nestačil by třeba jen takovýto výraz?
$text = '<p class="cl_odstavec">Lorem ipsum dolor žena amet.
Lorem ipsum dolor muž bmet. Lorem ipsum dolor žena cmet.
Lorem ipsum dolor sit dmet. Žena ipsum dolor sit emet.';
preg_match_all('~(?<=[>\.])\s*?([^\.]*žena.*\.)~Uius', $text, $matches);
var_dump($matches[1]);array 0 => string 'Lorem ipsum dolor žena amet.' (length=29) 1 => string 'Lorem ipsum dolor žena cmet.' (length=29) 2 => string 'Žena ipsum dolor sit emet.' (length=27) Hledá větu, kterou předchází mezery (ty hledá hladově) a před nimi je buď > (kvůli tomu html tagu) nebo tečka. |
||
| 1Pupik1989 Profil |
#7 · Zasláno: 20. 8. 2011, 09:28:53
Píšu z mobilu, tak to zkusim jen popsat. Pokud ta věta začíná velkým písmenem, tak to je náznak začátku. Do závorek přidat, že se v tom kusu stringu nesmí objevovat tečka. pak hledany vyraz a zakončit tečkou.Píšu z mobilu, tak to zkusim jen popsat. Pokud ta věta začíná velkým písmenem, tak to je náznak začátku. Do závorek přidat, že se v tom kusu stringu nesmí objevovat tečka. pak hledany vyraz a zakončit tečkou.
|
||
| 4ever Profil |
#8 · Zasláno: 21. 8. 2011, 21:10:14
Nejschůdnější cesta se mi zdá provádět dva regulární výrazy za sebou. Pro získání základních, nějakých hrubých a ještě nepřesných výsledků používám jeden výraz. To provádím ve fázi čtení dat ze souboru. Pak jsem si dopsal dodatečnou metodu, která profiltruje výsledky druhým regulárním výrazem a odstraní vše nepotřebné. Tím získám přesnější výsledek.
Takže to funguje asi takto: Mám smyčku while, ve které načítám jednotlivé soubory. Při jednom cyklu se načtou data z jednoho souboru v určitém rozsahu a provede se první preg_match. To se uloží do pole s výsledky. V témže cyklu pak ihned zpracovávám výsledky, připravuju je pro zápis do databáze, takže tam provádím i ten druhý preg_match. Jinak mám pocit, že čím více se používá .* tím víc to zpomaluje, a nejlepší je to omezit na určitý počet znaků .{0,40} apod. |
||
| 4ever Profil |
#9 · Zasláno: 23. 8. 2011, 22:09:24 · Upravil/a: 4ever
Ještě dolaďuji regulární výraz pro příkaz preg_replace a něco nefunguje úplně přesně jak bych chtěl. Tedy po předběžném vytažení odstavce, kde se vyskytují slova muž a žena chci smazat nežádoucí části.
@(.*)([Žž]ena.*[.,].*)(?:p>|br>|muž[, ])@su Má najít vše co se nachází kolem výskytu slova "žena" až po čárku nebo tečku (.*)([Žž]ena.*[.,].*) Jako upřesňující termín slouží (?:p>|br>|muž[, ]) který má říct, že tohle se už mazat nemá. Mazání se má zastavit před slovem muž. Problém je ale v tom, že se to vymaže včetně toho slova muž. Tedy příklad: $regex = "@(.*)([Žž]ena.*[.,].*)(?:p>|br>|muž[, ])@su"; $replacement = ""; $value = "Žena říkala, že muž dnes nemá chodit domů."; $vysledek = preg_replace($regex,$replacement,$value); echo $vysledek; By mělo vrátit $vysledek "muž dnes nemá chodit domů." Místo toho vrátí "dnes nemá chodit domů." Zřejmě příkaz pro nezachytávání nefuguje jak bych očekával. Nějaká rada? |
||
| YoSarin Profil |
Hmm a nebylo by nejjednodušší:
$sentences = explode('.', $text);
foreach ($sentences as $place => $sentence) {
if (mb_stripos($sentences, 'žena') === false) { // nevím jestli nebude problém s case-sensitivitou u ž, případně sem strčit ten regulár...
unset($sentences[$place]);
}
}Pokud trváš na regulárech, tak tenhle příspěvek buď přeskoč nebo ten regulár použij místo mb_stripos |
||
| 4ever Profil |
#11 · Zasláno: 23. 8. 2011, 23:31:42
YoSarin:
Reguláry jsou o něco inteligentnější. Na regulárech opravdu trvám. Potřebuju vysvětlit v čem je problém, že mi to nefunguje jak potřebuju. |
||
| 4ever Profil |
#12 · Zasláno: 24. 8. 2011, 08:18:19 · Upravil/a: 4ever
Už jsem našel řešení
V tomto případě jde o to, najít a smazat část věty začínající na Woman (žena) a končící slovem man (muž), věta začínající na slovo muž (opraveno) však už nemá být zahrnut do výsledku. // I replace part of sentence with regex: $regex = "@(.*)(woman.*[.,].*)(?:p>|br>|man[, ])@su"; // vymaže slovo muž $regex = "@(.*)(woman.*[.,].*)(?=p>|br>|man[, ])@su"; // nevymaže slovo muž $replacement = ""; $value = "Mike’s woman said, that her man shouldn’t come home."; $result = preg_replace($regex,$replacement,$value); echo $result; die(); Navíc jsem teď objevil jednu skvělou věc, kterou jsme myslém mohli řešit předchozí zadání: ?! "vyskytuje se tam, kde není daný výraz" např. script (?!error) - slovo "script" , které není následováno "error". |
||
| 1Pupik1989 Profil |
#13 · Zasláno: 24. 8. 2011, 08:46:36
zkusil bych jednoduše preg_splitem podle teček rozstríhat věty a pak preg_matchem vyhledal dané slovo. Nic krásného, ale je to postačující. Odpoledne zkusím něco vymyslet, jelikož mi to nedá spát a chci to do vyhledavacče, takže to stejně musím řešit.
|
||
| YoSarin Profil |
#14 · Zasláno: 24. 8. 2011, 10:30:17
4ever:
regexp je variabilnější, to ano, ale stejně bych se nebránil předchozímu rozsekání stringu na nejmenší možné úseky ve kterých chceš hledat (tzn. věty). Ten regexp to pak o něco zjednodušší... A co se odpovědí týká - pokd chceš do výsledku znovuzahrnout něco co ti regexp sežral, použij backreference: $regex = "@(.*)([Žž]ena.*[.,].*)(?:p>|br>|muž[, ])@su"; $replacement = "$3"; $value = "Žena říkala, že muž dnes nemá chodit domů."; $vysledek = preg_replace($regex,$replacement,$value); echo $vysledek; a co se týká tvého tvrzení: Má najít vše co se nachází kolem výskytu slova "žena" až po čárku nebo tečku (.*)([Žž]ena.*[.,].*) Tenhle regexp najde všechno kde je slovo žena a někde za ním čárka nebo tečka + všechno před slovem žena a všechno za čárkou|tečkou => to mi připadá jeko něco úplně jiného než co píšeš... Pokud chceš najít a smazat všechny úseky jedné věty, které začínají slovem woman a končí slovem man, tak by skoro bylo nejlepší ještě před samotným regexpem udělat následující: 1) odstranit html tagy, ať se v tom nepletou 2) rozsekat to podle teček do jednotlivých vět 3) na kroky 1 a 2 zapomeň, pokud to chceš provést na nějaké html stránce, kterou pak chceš při zachování formátování zobrazit v upravené podobě <?php $regex = '~(\W|^)woman(\W).*(\W(man\W))|(\.)~iU'; // ~ nebo @, to je jedno, já raději tildy $replace = '$1$4$5'; // $1 => znak před slovem woman, $4 => "man" na konci výběru (je-li), $5 => tečka na konci věty $value = "Mike’s woman said, that her man shouldn’t come home."; $result = preg_replace($regex, $replace, $value); echo $result; |
||
| 4ever Profil |
#15 · Zasláno: 24. 8. 2011, 12:42:59
YoSarin:
V konfiguraci skriptu na kterém pracuji jsou regulární výrazy a je jich tam více, tj. asi 8 regulárních výrazů + nějaké další pomocné prostředky, které vytvoří regulár automaticky z předem nakonfigurovaných voleb. Ta věc je trochu složitější, takže by rozsekání stringu jen omezilo konečné využití scriptu. Díky těm regulárům je skript dost dynamický, protože jako uživatel, který aspoň částečně ovládá reguláry, pak mohu snadno vyťukat co potřebuju a dostanu hledané výsledky. V opačném případě bych musel pokaždé přepisovat metody tak, aby vyhovovali hledacím kritériím. Html tagy jsou naopak pomocné k tomu, abych určil právě už v tom konfiguráku a slouží jako vodítka. Zrovna ty odstavce jsou klíčové a break line taky lecos napoví. Je dobré vědět kde končí a začíná věta což může být (?:^|\.) a (?:\.|$) a místy to používám k oříznutí věty. Ale současně využívám čárek protože nehledám slova v jiném pádu než v prvním. Takže muž[ ,.].* dává jistotu, že se tam nachází muž (je to vlastně hledání podmětu) a že to chci smazat. Naopak muž[ ,].* používám tam kde muže nechci smazat, ale vrátit včetně zbytku věty a možná až do konce odstavce. Takže s těmi reguláry se fakt dají dělat divy. Backreferences už místy používám, ale někde jinde. |
||
| YoSarin Profil |
#16 · Zasláno: 24. 8. 2011, 13:15:52
4ever:
Místo muž[ ,.].* (které bude mít problémy s muž: muž; "muž") bych zkusil muž\W (\W je zástupná sekvence pro "non-word" znak). Nerozumím úplně tomu jak se liší muž[ ,.].* a muž[ ,].*. Resp vím jaký je mezi těmito dvěma reguláry rozdíl, ale nedochází mi souvislost s mazáním - replace maže všechno co vyhovuje dané podmínce a nahradí to jiným stringem (který může obsahovat části z toho nalezeného). Zkoušel jsi ten můj kód (ten poslední)? Podle mě vyhovuje tomu o co se snažíš v [#12] (nebo jsem nepochopil čeho chceš dosáhnout). Jen tam chybí ukončení v případě že narazíš na nějaký tag... |
||
| 4ever Profil |
#17 · Zasláno: 24. 8. 2011, 13:49:19 · Upravil/a: 4ever
YoSarin:
„Nerozumím úplně tomu jak se liší muž[ ,.].* a muž[ ,].*.“ Tak v tomto případě asi myslíš muž[ ,.].* a muž[ ,].*\. Ten první definitivně potvrzuje, že věta může končit slovem muž. Což je zrovna ten případ, který nehledám "Moje žena chce vědět, co dělá tvůj muž.". Hledám podmět; a podmět pokračuje nějakým slovem např. "muž, který šel" nebo "muž běží". „Zkoušel jsi ten můj kód (ten poslední)?“ Vrací to "Mike’s man shouldn’t come home." místo "man shouldn’t come home." To s těma tečkama a čárkama je inteligentnější. „nebo jsem nepochopil čeho chceš dosáhnout“ Ty reguláry jsou závislé na tom, co přesně hledám v tom textu a jakým způsobem ten text je psaný. Takže já třeba vím je "muž;" nebo "muž:" se tam nevyskytuje. To o co tam jde je v prvním případě vrátit pouze věty kde se vyskytuje muž, a v druhém případě pouze ty věty kde se vyskytuje žena. Pod slovem věta, ale rozuměj taky části věty, nejen něco co končí tečkou. Tzn. pokud kontext začíná o ženě, ale hledám muže, pak větu o ženě smazat, větu o muži nechat. A když začíná další věta o ženě, tak ji zase smazat. To vše se vztahuje pouze na první odstavec. Přitom musí být zachována jakž tak srozumitelnost o čem ta věta je, takže já tam ještě zahrnuji zvratné zájmeno "se", které se občas objevuje před podmětem. Jak říkám, vyřešil jsem to tak, že používám dva reguláry, nejdříve hledání věty o muži (preg_match) a pak odfiltrování/smazání vět o ženě (preg_replace). To s tou ženou a mužem bylo nejtěžší. Pak mám ještě další slova, která hledám ve výsledcích, ale tam už je to jednodušší. |
||
| YoSarin Profil |
#18 · Zasláno: 24. 8. 2011, 14:04:00
4ever:
„Tak v tomto případě asi myslíš muž[ ,.].* a muž[ ,].*\.“ Tečka na konci nepatřila do regexpu, jen ukončuje větu začínající "Nerozumím". Myslím přesně to, cos napsal ty: Takže muž[ ,.].* dává jistotu, že se tam nachází muž (je to vlastně hledání podmětu) a že to chci smazat. Naopak muž[ ,].* používám tam kde muže nechci smazat, ale vrátit včetně zbytku věty a možná až do konce odstavce. -> faktický rozdíl mezi těmi regexpy je mi znám, prvnímu vyhovuje slovo muž následované mezerou, čárkou nebo tečkou a druhému slovo muž následované pouze mezerou nebo čárkou. Nevidím souvislost mezí těmito výrazy a tím jestli se slovo muž smaže nebo ne. > Vrací to > "Mike’s man shouldn’t come home." místo > "man shouldn’t come home." Ano, protože to bylo zadání: V tomto případě jde o to, najít a smazat část věty začínající na Woman (žena) a končící slovem man (muž), muž však už nemá být zahrnut do výsledku. Pokud už jsi dosáhl toho o co ti šlo, tak asi nemá smysl se tu v tom dál patlat, navíc mám pocit že mi pořád tak trochu ujíždí vlak :). Ale pokud chceš dělat jazykový parser pomocí regexpů, tak hodně štěstí, ale imo to není nejšťastnější cesta... |
||
| Majkl578 Profil |
#19 · Zasláno: 24. 8. 2011, 18:18:57
[#12] 4ever:
„Navíc jsem teď objevil jednu skvělou věc, kterou jsme myslém mohli řešit předchozí zadání“ Gratuluji k objevení Ameriky, ale já tohle použil už v příspěvku [#6], který jsi naprosto ignoroval. Jak to tak vidím, vypadá to, že na to co řešíš (a do čeho ses tu docela zamotal nebo jen nedokázal jednoznačně vysvětlit) by se více hodil nějaký tokenizer/lexer, který by to celé rozdělil podle mezer a interpunkce, následně se to prošlo, odfiltrovalo nevhodné části (věty) a sloučilo zpět. |
||
| 4ever Profil |
#20 · Zasláno: 25. 8. 2011, 11:35:31 · Upravil/a: 4ever
Majkl578:
To že jsem na tvůj příspěvek nereagoval, nebylo že bych ho nečetl. Ale nebyl tam ten výraz, který by hledal všechny znaky, ve kterých by nebylo to druhé slovo. Zkoušel jsem to všemožně a pak došel k závěru, že je to zbytečné a nejspíš to ani přes regulár nejde. Sice existují pomůcky jako (?!slovo) nebo (?!(slovo|slovo2)) ale to zase nezahrnuje .* a když použiješ .* tak se ve výsledku zase může objevit slovo, které nechceš. Prostě jednodušší je vytáhnout nejdříve nějaký hledaný základ a potom teprve odstranit nežádoucí části. Navíc, proč bych měl ten svůj script předělávat, když už ho mám hotový a funkční? Prohledání asi 30 souborů trvá 4 vteřiny. Získávám nejdříve nějaké základní věty a pak výsledky filtruju ještě jednou, abych získal detailnější informace a to ukládám zvlášť. |
||
|
Časová prodleva: 14 let
|
|||
0