Diskuze: Regulární výrazy


hanpari:12.5.2014 21:06
Jsi si jistý, že na to potřebuješ regex? Přijde mi, že to chceš dostat z pevného formátu, na který ti stačí slicing.
Jinak můžeš zkusit tohle:
https://pythex.org/?…\D{3}%20\D{3}%20\d\d%20\d\d%3A\d\d%29&test_string=vesparie%20pts%2F0%20%3A0%20Mon%20May%2012%2017%3A59%20-%20down%20%2800%3A01%29&ignorecase=0&multiline=0&dotall=0&verbose=0
Ahoj.
Nechci otevírat další vlákno, tak se zeptám sem.
Potřebuju regulární výraz, který mi najde shodu v URL adresách (jsou to detaily hotelu), které vypadají nějak takto:
čistá jednoduchá
https://www.travelasap.cz/…rsko/186092a
nebo s parametry
https://www.travelasap.cz/…rsko/186092a?…
Problém je, že existují i adresy, které mají za tím 186092a ještě třeba /169044762d (jsou to detaily termínu u toho hotelu):
čistá jednoduchá
https://www.travelasap.cz/…a/169044762d
nebo s parametry
https://www.travelasap.cz/…a/169044762d?…
Ty druhé (detaily termíny hotelu) vybrat umím (i když nevím, jestli je to to nejlepší řešení):
(https:\/\/www.travelasap.cz\/chcete-jet-do\/)(([a-z-]\/)+)([0-9][0-9]a)\/([0-9][0-9]d)(\?{0,1}.)
Ale neumím upravit regulární výraz tak, aby vyloučil tu část s tím
169044762d, tzn. aby vybral ten první.
Kompletní sadu testovacích adres a regulární výraz mám tady: https://regexr.com/4he84
Mohl by mi někdo poradit, jak upravit ten výraz, aby to vybralo jenom ty,
kde chybí ta část /169044762d (respektive obecněji kde chybí to
\/([0-9][0-9]*d) )??? Protože pouhým negováním té závorky to nefunguje
Děkuji moc.
Petr
Martin Petrovaj:14.7.2019 23:19
Nie som si istý, či úplne rozumiem tvojmu zadaniu, ale fungovalo by toto?
^(https:\/\/www.travelasap.cz\/chcete-jet-do\/)(([a-z-]+\/)+)([0-9][0-9]*a)((\?|\#).+)*$
Akurát nezabudni, že ak to budeš chcieť použiť na texte, ktorý obsahuje viac adries v niekoľkých riadkoch, tak potrebuješ zapnúť multiline modifier. Ako - to si už musíš nájsť sám, líši sa to od jazyka k jazyku a od jedného flavoru regexu k druhému.
Urcite by bylo lepsi zalozit vlastni tema nez otevirat s novym zadanim tema z 2014.
Zadani moc nerozumim. Zkus dat treba 5-10 adres a jaky by mel byt vystup?
Kdyby bylo na mne, tak pouziji treba explode a nebo callback.
Jakoze to rozsekam podle lomitka. Pak sloupec po sloupci ocesu reg. vyrazem a
vysledek porozvnam s nejakym seznamem.
$url = "..."
$arr = explode('/', $url);
foreach ($arr as $value)
{
$str = preg_replace('...', $value);
if ($str!=="") check($db, $str);
}
A mozna by slo pouzit i toto, nejak
https://www.php.net/…arse-url.php
Petr Vavřinec:15.7.2019 17:50
Děkuji, ale ten výraz mi nefunguje OK, zkusím to předefinovat srozumitelněji.
Zadání je získat dva regulární výrazy pro Hotjar, aby mi každá ze dvou
heatmap monitorovala jiný typ stránky.
Prvním typem stránky jsou detaily hotelu. Jejich "vzor" URL je
následující:
https://www.travelasap.cz/chcete-jet-do/ - tohle je tam
vždycky
jmeno-hotelu/ - tohle je tam vždycky, jsou tam malá písmena a mohou tam být
i pomlčky (častý případ) nebo čísla (řídký případ)
jmeno-zeme/ - tohle je tam vždycky, jsou tam malá písmena a mohou tam být i
pomlčky
jmeno-destinace/ - tohle tam není vždycky, ale většinou, navíc se to může
objevit i vícekrát ( {0,3} ), jsou tam malá písmena a pomlčky
xxxxxxxa - tohle je tam vždycky, je to skupina číslic (proměnlivé délky)
ukončená písmenem a
Potom se tam může (ale nemusí) objevit ? nebo # a pak další paramety (třeba UTM parametry atd.), takže to mohou být velká i malá písmena, číslice, &, = a pomlčka...
Příklad:
https://www.travelasap.cz/…novi/201919a
nebo s parametry:
https://www.travelasap.cz/…novi/201919a?…
No a to neumím vybrat. Jde o to, že pokud se za tím xxxxxa objeví ještě /xxxxxxxd, čili lomítko, skupina čísel a písmenko d, tak už to není detail hotelu, ale detail konkrétního dovolenkového termínu v daném hotelu a to je trochu jiná stránka, u které potřebuju jiný regulární výraz a jinou heatmapu.
Takže druhý typ URL je detail konkrétního termínu, pro kterou potřebuju
druhý regulární výraz. Fungobval mi na to tenhle:
(https:\/\/www.travelasap.cz\/chcete-jet-do\/)(([a-z-]\/)+)([0-9][0-9]a)\/([0-9][0-9]d)(\?{0,1}.)
Příklad (stejný hotel jako nahoře, akorát je to konkrétní termín,
takže vlastně stejná URL, jen navíc to /181308076d):
https://www.travelasap.cz/…a/181308076d
nebo s parametry (bez UTM)
https://www.travelasap.cz/…a/181308076d?sm=1
nebo jen s UTM parametry
https://www.travelasap.cz/…a/181308076d?…
nebo jak s UTM parametry, tak s parametry pro aplikaci
https://www.travelasap.cz/…a/181308076d?…
Snad jsem to teď popsal lépe... I když nevím, jestli mi rozumíte.
Petr V.
Martin Petrovaj:15.7.2019 18:00
Myslím, že zadaniu rozumiem, len škoda, že si nenapísal aj prečo ti ten výraz predtým nefunguje.
Prepáč že sa opakujem, ale určite si mal zapnutý multiline modifier? Na
tej stránke, kde si to testoval si ho zapneš takto:
http://prntscr.com/ofch5z
Ak by si ho chcel použiť v Javascriptovom kóde, tak akurát potrebuješ za to druhé lomítko pridať ešte písmeno "m" (ako je na tej stránke tiež naznačené).
Niektoré flavory regexu podporujú aj formu "(?m)zvysokRegexu". Javascript to ale AFAIK nepodporuje.
Ak je problém inde, tak skús napísať kde a budem ti vedieť poradiť lepšie. Možno tam naozaj mám nejakú logickú chybu, alebo potrebuješ iný prístup než regex.
Si zkus udelat jednoduchy parsovac, kdyz to nefunguje. (do pythonu si to prepises, bych musel hledat v neprehledne dokumentaci vhodne prikazy, coz se mi fakt jako nechce)
<?php
@ini_set('error_reporting', E_ALL);
@ini_set("display_errors", "on");
error_reporting(E_ALL);
function escapeHtml($str) {return htmlspecialchars($str);}
$url_all = explode("\n", "
https://www.travelasap.cz/chcete-jet-do/m-1/bulharsko/primorsko/186092a
https://www.travelasap.cz/chcete-jet-do/m-1/bulharsko/primorsko/186092a?es=0&sb=1&ci%5B0%5D=35&di%5B0%5D=1557&pa=2&sm=1
https://www.travelasap.cz/chcete-jet-do/m-1/bulharsko/primorsko/186092a/169044762d
https://www.travelasap.cz/chcete-jet-do/m-1/bulharsko/primorsko/186092a/169044762d?es=0&sb=1&ci%5B0%5D=35&di%5B0%5D=1557&pa=2&sm=1
https://www.travelasap.cz/chcete-jet-do/
https://www.travelasap.cz/chcete-jet-do/iberostar-herceg-novi/cerna-hora/herceg-novi/201919a
https://www.travelasap.cz/chcete-jet-do/iberostar-herceg-novi/cerna-hora/herceg-novi/201919a?utm_source=Google&utm_medium=product&utm_content=detail-hotelu&utm_campaign=osvedcene-hotely-egypt#tab-informace
https://www.travelasap.cz/chcete-jet-do/iberostar-herceg-novi/cerna-hora/herceg-novi/201919a/181308076d
https://www.travelasap.cz/chcete-jet-do/iberostar-herceg-novi/cerna-hora/herceg-novi/201919a/181308076d?sm=1#fi-lm=0
https://www.travelasap.cz/chcete-jet-do/iberostar-herceg-novi/cerna-hora/herceg-novi/201919a/181308076d?utm_source=Google&utm_medium=product&utm_content=detail-hotelu&utm_campaign=osvedcene-hotely-egypt
https://www.travelasap.cz/chcete-jet-do/iberostar-herceg-novi/cerna-hora/herceg-novi/201919a/181308076d?sm=1&utm_source=Google&utm_medium=product&utm_content=detail-hotelu&utm_campaign=osvedcene-hotely-egypt#fi-lm=0
");
unset($url_all[count($url_all)-1]);
unset($url_all[0]);
$patt_all = array(
'jmeno-hotelu' => '~^[a-z0-9-]+$~', // tady jsem pridaval cisla pro 'm-1'
'jmeno-zeme' => '~^[a-z-]+$~',
'jmeno-destinace' => '~^[a-z-]+$~',
'xxxxxxxa' => '~^\d+a$~',
'dovolenkovy-termin' => '~^\d+d$~',
'parametry' => '~[#?].*$~'
);
function parametryCb($matches)
{
global $row;
$row['parametry'] .= $matches[0].', ';
return '';
};
$row_all = array();
foreach ($url_all as $item)
{
$row = array();
$row['parametry'] = '';
$item = preg_replace_callback($patt_all['parametry'], 'parametryCb', $item);
$part_all = explode("/", $item);
// $part_all = preg_split("~[/#?]~", $item);
$next = 0;
foreach($part_all as $index=>$part)
{
if ($index<3)
{continue;}
if ($index==4)
{
$key = 'jmeno-hotelu';
if (preg_match($patt_all[$key], $part))
{
$row[$key] = $part;
continue;
}
}
if ($index==5)
{
$key = 'jmeno-zeme';
if (preg_match($patt_all[$key], $part))
{
$row[$key] = $part;
continue;
}
}
if ($index>5 && $index<9)
{
$key = 'jmeno-destinace';
if (preg_match($patt_all[$key], $part))
{
$row[$key] = $part;
$next++;
continue;
}
}
if ($next>0)
{
$key = 'xxxxxxxa';
if (preg_match($patt_all[$key], $part))
{
$row[$key] = $part;
continue;
}
$key = 'dovolenkovy-termin';
if (preg_match($patt_all[$key], $part))
{
$row[$key] = $part;
continue;
}
$key = 'parametry';
if (preg_match($patt_all[$key], $part))
{
$row[$key] = $part;
$bool_destinace = true;
continue;
}
}
}
$row_all[] = $row;
}
//echo 'aaa';
$tbody = '';
$tbody .= '<tr>';
foreach ($patt_all as $key=>$patt)
{
$tbody .= '<td><b>'.escapeHtml($key).'</b></td>';
}
$tbody .= '</tr>';
foreach ($row_all as $row)
{
$tbody .= '<tr>';
foreach ($patt_all as $key=>$patt)
{
$value = isset($row[$key]) ? $row[$key] : '';
$tbody .= '<td>'.escapeHtml($value).'</td>';
}
$tbody .= '</tr>';
}
echo '<table border=1>'.$tbody.'</table>';
// vypise
<table border=1>
<tr><td><b>jmeno-hotelu</b></td><td><b>jmeno-zeme</b></td><td><b>jmeno-destinace</b></td><td><b>xxxxxxxa</b></td><td><b>dovolenkovy-termin</b></td><td><b>parametry</b></td>
</tr>
<tr><td>m-1</td><td>bulharsko</td><td>primorsko</td><td></td><td></td><td></td>
</tr>
<tr><td>m-1</td><td>bulharsko</td><td>primorsko</td><td>186092a</td><td></td><td>?es=0&sb=1&ci%5B0%5D=35&di%5B0%5D=1557&pa=2&sm=1 , </td>
</tr>
<tr><td>m-1</td><td>bulharsko</td><td>primorsko</td><td>186092a</td><td></td><td></td>
</tr>
<tr><td>m-1</td><td>bulharsko</td><td>primorsko</td><td>186092a</td><td>169044762d</td><td>?es=0&sb=1&ci%5B0%5D=35&di%5B0%5D=1557&pa=2&sm=1 , </td>
</tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr><td>iberostar-herceg-novi</td><td>cerna-hora</td><td>herceg-novi</td><td></td><td></td><td></td>
</tr>
<tr><td>iberostar-herceg-novi</td><td>cerna-hora</td><td>herceg-novi</td><td>201919a</td><td></td><td>?utm_source=Google&utm_medium=product&utm_content=detail-hotelu&utm_campaign=osvedcene-hotely-egypt#tab-informace , </td>
</tr>
<tr><td>iberostar-herceg-novi</td><td>cerna-hora</td><td>herceg-novi</td><td>201919a</td><td></td><td></td>
</tr>
<tr><td>iberostar-herceg-novi</td><td>cerna-hora</td><td>herceg-novi</td><td>201919a</td><td>181308076d</td><td>?sm=1#fi-lm=0 , </td>
</tr>
<tr><td>iberostar-herceg-novi</td><td>cerna-hora</td><td>herceg-novi</td><td>201919a</td><td>181308076d</td><td>?utm_source=Google&utm_medium=product&utm_content=detail-hotelu&utm_campaign=osvedcene-hotely-egypt , </td>
</tr>
<tr><td>iberostar-herceg-novi</td><td>cerna-hora</td><td>herceg-novi</td><td>201919a</td><td>181308076d</td><td>?sm=1&utm_source=Google&utm_medium=product&utm_content=detail-hotelu&utm_campaign=osvedcene-hotely-egypt#fi-lm=0 , </td>
</tr>
</table>
Martin Petrovaj děkuju moc!!! Už jsem to pochopil. Proč jsem to nechápal předtím bylo to, že ten můj výraz pro detail termínu fungoval na těch vzorových datech i když jsem neměl zapnutý ten flag pro multiline, protože jsem ve výrazu nepoužil uvozování na začátek a konec vzorku. Byla to ta lehčí varianta, které bylo snadné vyhovět i bez toho multilinu. Takže ano, ten tvůj původní výraz byl řešení a moc děkuju. Trochu jsem ho rozšířil o velká písmena v parametrech a mám to vyřešené. Teď to zkusím vložit do Hotjaru a uvidím, jestli ten jejich urlparser (nebo jak to nazvat) bude umět rozlišit detaily hotelu od detailu termínu. To by mi moc pomohlo. Díky moc!
Takže tomuto výrazu:
^(https:\/\/www.travelasap.cz\/chcete-jet-do\/)(([a-z0-9-]+\/)+)([0-9][0-9]*a)((\?|\#){0,1}[0-9A-Za-z_=&-]*)*$
vyhovují všechny mnou otestované adresy stránek s detaily hotelu, zatímco detaily termínu nevyhovují. To je to, co jsem chtěl.
A tomuto výrazu:
^(https:\/\/www.travelasap.cz\/chcete-jet-do\/)(([a-z0-9-]+\/)+)([0-9][0-9]*a)\/([0-9][0-9]*d)((\?|\#){0,1}[0-9A-Za-z_=&-]*)*$
vyhovují všechny mnou otestované adresy stránek s detaily termínu, ale detaily hotelů nevyhovují. Super.
Opravdu si vážím času, který si tomu věnoval.
Petr V.
Peter Mlich Ups... Tolik práce, tolik kódu... Děkuju za ten čas.
Není to přesně to, co jsem hledal, ale už teď mne napadá jedna věc, na kterou to použiju. Protože jestli to chápu, není to jen normální split/rozložení řetězce, ale zároveň díky těm regexům těm parciálním částem přiřadíš i význam...
To se může hodit. Nejenom mně.
Děkuju.
Petr V.
Peter Mlich:17.7.2019 8:16
Tak, vysledkem je ta tabulka, html kod dole. Si to zkopiruj na plochu do
soubor.html a spust
Melo by to jit zapsat takto:
[0-9][0-9]* === [0-9]+ === [0-9]{1,}
(\?|\#){0,1} === [?#]? === [?#]{,1}
resp, i s temi zavorkami, pokud s tim potrebujes dal pracovat
[0-9A-Za-z_=&-]* === .*
Toto nechapu. ?# se muze vyskytnout, myslim si, jen jednou. A je jedno, co tam za nim bude, ne? .* by to mela pokryt, asi, ne?
(([a-z0-9-]+\/)+)([0-9][0-9]*a)
A tohle je celkem zajimavy orisek
[a-z0-9-]+ <=== [0-9][0-9]*
cili, ten prvni vyraz pokryje i tento nasledujici, mozna, leda bys to napsal takto
[a-z][a-z0-9-]+
ze prvni musi byt vzdy pismeno a pak jeden ze znaku [a-z0-9-]
A k obema bych mozna pridal min-max pocet znaku.
^(https:\/\/www.travelasap.cz\/chcete-jet-do\/)
^([^/]+[/]){4})
preskoc prvni 4 lomitka, [^/]+ === cokoliv, co neni lomitko a 1 a vice
znaku
Ale mozna, to tridis podle adresy i z jinych zdroju.
Nebylo to tak tezke udelat, vidis, ze ten kod je vicemene copy-paste. Hlavne je tam videt, co se kdy priradi a kam. V tvem regularnim vyrazu neresis moc poradi vyrazu.
ostatne, to php pujde spustit nekde online, dole je pak Execute code. Napisu
jim, ze output by mohly dat i html
http://sandbox.onlinephpfunctions.com/…9c41df3f9003
http://phptester.net/ -
tady to sice dava html vystup, ale nejde to ulozit asi bez registrrace
Tohle je taky pomerne zajimavy priklad, ktery by mozna cely ten muj kod
zjednodusil.
https://www.rexegg.com/regex-php.html
$airports= 'San Francisco (SFO) USA
Sydney (SYD) Australia
Auckland (AKL) New Zealand';
$regex = '%(?m)^\s*+([^(]+?)\s\(([^)]+)\)\s+(.*)$%';
$hits = preg_match_all($regex, $airports, $matches, PREG_PATTERN_ORDER);
/*
Array
(
[0] => Array // The Whole Matches
(
[0] => San Francisco (SFO) USA
[1] => Sydney (SYD) Australia
[2] => Auckland (AKL) New Zealand
)
[1] => Array // The Group 1 Matches
(
[0] => San Francisco
[1] => Sydney
[2] => Auckland
)
[2] => Array // The Group 2 Matches
(
[0] => SFO
[1] => SYD
[2] => AKL
)
[3] => Array // The Group 3 Matches
(
[0] => USA
[1] => Australia
[2] => New Zealand
)
)
*/
(?m) - vyber cely radek
^\s*+ - text po prvni mezeru
( [^(]+?) - text bez zavorky po prvni zavorku
\s - oddelovac mezera
\(([^)]+)\) - zavorka ( vnitrek ) zavorka
\s+ - oddelovac mezera 1 a vice
(.*)
Zobrazeno 15 zpráv z 15.