Autor Zpráva
MTF
Profil
Zdravím a prosím o pomoc. Nedaří se mi sestavit regulární výraz pro ověření jména souboru v tomto tvaru:
01-02-03-04.html - název souboru může obsahovat libovolný počet 2-ciferných subnázvů oddělených pomlčkou.
Potřebuji pomoci fce preg_match ověřit správný tvar názvu souboru tak, aby parametr matches obsahoval jednotlivé části nazvu souboru. Zkoušel jsem toto:
^(\d{2})(?:-(\d{2}))*\.html$
ale takto matches obsahuje jen 1. a poslední část názvu, tedy:
array(3) { [0]=> string(17) "01-02-03-04.html" [1]=> string(2) "01" [2]=> string(2) "04" }
Neví prosím někdo, jak zapsat správný reg výraz?

Moderátor Joker: Titulek „další regulární výraz :)“ nevystihoval podstatu dotazu. Příště zkus prosím vymyslet lepší.
juriad
Profil
MTF:
Snažíš se provádět příliš věcí najednou.
Můžeš napřed jen zkontrolovat, že název odpovídá požadavkům, a pak ho rozdělit na jednotlivé části:

function parseFileName($fileName) {
        if (! preg_match('/^\d\d(-\d\d)*\.html$/', $fileName)) {
                return FALSE;
        }

        return explode('-', substr($fileName, 0, strlen($fileName) - 5));
}

$name = '01-02-03-04.html';
var_dump(parseFileName($name));
Joker
Profil
MTF:
Poznámka: Skoro mi připadá, že když se diskuse brání titulkům „Problém“, část tazatelů místo „problém“ používá „regulární výraz“.
Většina dotazů pojmenovaných „Regulární výraz“ řeší nějaký konkrétní problém (tady rozdělení řetězce podle pomlčky) a regulární výraz tazatel předpokládá jako možné řešení. Přitom často regulární výraz není nejlepší řešení tazatelova problému (někdy dokonce problém ani rozumným způsobem přes RV řešit nejde).

Jinak řešil bych to taky přes explode, jako juriad.
MTF
Profil
Díky za hbitou odpověď. Takže to nejde? Potřeboval jsem ten reg výraz pro porovnávací funkci pro usort. Jde o to, že tvar jména souboru by se mohl časem měnit např. na A_01-02-03.html. Tím pádem by se musela Tvoje funkce předělat. Ideální by bylo najít ten správný regex pokud to jde :-)


BTW: taky bych to řešil přes explode, kdyby to šlo :-)
juriad
Profil
MTF:
Myslím, že to přes regex nejde. V regexu vždy uvedeš jen konečný počet závorek (vzorů k zapamatování) a stejný počet bude ve vystupním poli matches.

Pěkně to lze ilustrovat na příkladu:
$names = array('a-bb-c-dd-e-ff-', 'a-b-c-d-e-f-', 'aa-bb-cc-dd-ee-ff-', 'aa-b-cc-d-ee-f-');

foreach ($names as $name) {
        preg_match('/^(?:(?:(\w)|(\w)(\w))-)*$/', $name, $matches);
        var_dump($matches);
}

Zkus popsat celý svůj problém s řázením, třeba to půjde vyřešit nějak jednoduše a možná nebudou regulární výrazy nakonec třeba. :)
peta
Profil
$str = "01-02-03-04.html";
$arr = explode('.',$str);
$arr = explode('-',$arr[0]);
print_r($arr[0]);

01-02-03-04.html - ^\d+(-\d+){3}\.html$ (tez vyhovuje pro 000-0-0-000.html)
A_01-02-03.html - ^\w+_\d+(-\d+){2}\.html$ (tez vyhovuje pro xAss_0-000-000-0.html)
http://www.regexp.cz/index.php
Zvlastni, ze dvojka vyhovuje i 0A_01-02-03.html podle regexp.cz pro PHP preg.
Samozrejme, muzes dusledne vyzadovat presne 2 cislice a aby byla prvni nula a pod. To zalezi na tobe.
MTF
Profil
juriad:
Ok, tušil jsem, že bude problém s těma subvýrazama :( Můj problém s řazením je prostý. Potřebuji ty soubory seřadit vzestupně dle abecedy (tedy číselné části řadit jako čísla a zbytek dle abecedy). Pomocí sort se mi to nedaří, proto jsem šel cestou usort. Pokud by byl tvar názvu souboru neměnný (tedy měl by omezený počet "subnázvů" třeba na 4, např. 01-02-03-04.html) tak s tím nemám problém. Ale chtěl jsem to udělat maximálně univerzální :-)
Radek9
Profil
MTF:
Možná se podívej spíš na natsort. Není to to, co hledáš?
MTF
Profil
Radek9:
Úžasná funkce :-) to jsem přesně potřeboval. Jak to, že tu funkci neznám? :-)
Díky!
peta
Profil
Nemyslim, ze je to rozumny napad psat vlastni serazovani. Jak seradis:
01-02-03-04.html // 1-2
01-020-03-04.html // 1-20
1-02-03-04.html // 1-2
001-02-03-04.html // 1-2
010-02-03-04.html //10-2

<script>
function sort_cb1(a,b)
{
return a - b;
}

function sort_cb2(a,b)
{
var i,l;
a = a.split('-');
b = b.split('-');
l = a.length<b.length ? a.length : b.length;
for (i=0;i<a.length;i++)
    {
    if (sort_cb1(parseInt(a[i]),parseInt(b[i]))>0) return 1;
    }
return -1;
}

var t, arr;
str = "\
01-02-03-04.html,\
01-020-03-04.html,\
1-02-03-04.html,\
001-02-03-04.html,\
010-02-03-04.html,\
001-20-03-04.html\
"
arr = str.split(",");
t  = arr.join(",\n")+"\n\n";
arr = str.split(",");
arr.sort(); // klasicky string sort
t += arr.join(",\n")+"\n\n";
arr = str.split(",");
arr.sort(sort_cb2); // rozparsovani a ciselny sort (serazuje, ikdyz je druhy string delsi a=1-2-3, b=1-2-3-4
t += arr.join(",\n")+"\n\n";
alert(t);

</script>
MTF
Profil
Tak jsem se radoval předčasně :( ani natsort nesetřídí přirozeně tyto hodnoty:
01.html
02.html
02-01.html
03.html
Jak to jenom ten Total Commander dělá? :-)


Joker:
a prosím moderátora, aby změnil zpět název diskuze na původní, případně na "Jak přirozeně setřídit pole"
Díky!
peta
Profil
MTF:
Mozna by bylo fajn dat sem priklad, jak to serazene potrebujes a proc to povazujes za prirozenejsi nez jine? Ja tu treba TC nemam a instalovat to na firemni pc ani nebudu.
MTF
Profil
peta:
Soradž, potřebuji to řadit přesně tak, jak je to uvedené v příspěvku #11. Všechny ostatní funkce to řadí v tomto pořadí:
01.html
02-01.html
02.html
03.html

Kdyby na to existovala nativní php funkce, bylo by vše ok. Já jsem šel cestou reg výrazů a tam jsem pohořel na subvýrazech. Ale když použiji pevnou hloubku názvu souboru, např.: 01.html ... 99-99-99-99-99.html, tedy jakoby 5 úrovní názvu, mohu situaci řešit vlastní sortovací funkcí přes usort:
  private function cmp($a, $b) {
    $ma = array();
    $mb = array();
    preg_match(REGEX, $a, $ma);
    preg_match(REGEX, $b, $mb);
    for ($i=1; $i<count($ma); $i++) {
      if ($ma[$i] != $mb[$i]) return $ma[$i] < $mb[$i] ? -1 : 1;
    }
    return 0;
  }
kde REGEX je '/^(\\d{2})(?:-(\\d{2}))?(?:-(\\d{2}))?(?:-(\\d{2}))?(?:-(\\d{2}))?\\.phtml$/'
Šlo mi ale od začátku o to, abych nemusel omezovat počet "levelů" v názvu souboru.
peta
Profil
Porovnava i delku retezce. To je to, na co jsem v te moji js verzi upozornoval, ze to tam nemam zabudovane. Muzes udelat vlastni funkci, ktera vyuzije serazeni a,b podle natsort a pak to jeste porovnat na delku retezce a vratit vysledek. Viz, jak jsem to resil s tim JS, taky predavam sortu vlastni funkci.
Tve serazovani mozna bude neco super, ale pro vic polozek to bude pomale a budes zatezovat stroj s php. Jestli to za to stoji? TC zatezuje stroj uzivatele, ne server.
MTF
Profil
peta:
Ok, díky moc za rady..
Tori
Profil
Dá se to udělat i takhle - reguláry se použijí méněkrát, než kdy byly v řadicí funkci:

$pole = array('01.html', 'A_02.html', '02.html', '02-01.html', '03.html', );
$tmp = array();
foreach ($pole as $name) {
    $tmp[$name] = preg_replace('~^\D*|\D*$~', '', $name);
}
asort($tmp);
$pole = array_keys($tmp);
var_dump($pole);
Nevím, kam byste řadil ten druhý prvek, jestli před nebo za 02.html. Řazení za se dá docílit změnou reguláru.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: