2010-03-28 10 views
6

Chcę być zdolne do analizowania ścieżki plików jak ten:Wyrażenie regularne pasujące do nieograniczonej liczby opcji

/var/www/index.(htm|html|php|shtml) 

do uporządkowanej tablicy:

array("htm", "html", "php", "shtml") 

a następnie produkować listę alternatyw :

/var/www/index.htm 
/var/www/index.html 
/var/www/index.php 
/var/www/index.shtml 

teraz mam preg_match oświadczenie, że może podzielić dwa alternatywy:

preg_match_all ("/\(([^)]*)\|([^)]*)\)/", $path_resource, $matches); 

Może ktoś dać mi wskaźnik Jak przedłużyć to zaakceptować nieograniczoną liczbę alternatyw (co najmniej dwóch)? Tylko w odniesieniu do wyrażenia regularnego, reszta, z którą mogę sobie poradzić.

Zasada jest taka:

  • Lista musi zacząć ( i ścisłej z )

  • Musi istnieć jeden | na liście (czyli co najmniej dwie alternatywy)

  • Wszelkie inne wystąpienia ( lub ) mają pozostać nietknięte.

Aktualizacja: muszę być w stanie poradzić sobie również z wieloma parami nawiasów, takich jak:

/var/(www|www2)/index.(htm|html|php|shtml) 

przykro mi powiedzieć, że nie od razu.

UPDATE 2: Jeśli szukasz zrobić to, co usiłuję zrobić w systemie plików, a następnie zwrócić uwagę, że glob() przynosi już tę funkcję po wyjęciu z pudełka. Nie ma potrzeby wdrażania niestandardowego solutiomu. Zobacz odpowiedź @ Gordona poniżej, aby uzyskać szczegółowe informacje.

+1

Dlaczego do cholery jest każdy * * Obsesję ** z regex? Po prostu użyj innej cholernej metody. Dopasowanie wszystkiego po nawiasie ** nie jest trudne ** bez wyrażeń regularnych. –

+0

@Coronatus pokazuje mi elegancką, lekką metodę bez regex, która może 1. radzić sobie z wieloma parami nawiasów i 2. ignorować pary nawiasów, które nie zawierają '|' i nie wygląda jak gówno, a ja ' Z radością ściągnę dla ciebie kapelusz. –

+1

Gotowe. Zobacz moją odpowiedź. –

Odpowiedz

3

rozwiązanie dla regex :)

<?php 

$test = '/var/www/index.(htm|html|php|shtml)'; 

/** 
* 
* @param string $str "/var/www/index.(htm|html|php|shtml)" 
* @return array "/var/www/index.htm", "/var/www/index.php", etc 
*/ 
function expand_bracket_pair($str) 
{ 
    // Only get the very last "(" and ignore all others. 
    $bracketStartPos = strrpos($str, '('); 
    $bracketEndPos = strrpos($str, ')'); 

    // Split on ",". 
    $exts = substr($str, $bracketStartPos, $bracketEndPos - $bracketStartPos); 
    $exts = trim($exts, '()|'); 
    $exts = explode('|', $exts); 

    // List all possible file names. 
    $names = array(); 

    $prefix = substr($str, 0, $bracketStartPos); 
    $affix = substr($str, $bracketEndPos + 1); 
    foreach ($exts as $ext) 
    { 
     $names[] = "{$prefix}{$ext}{$affix}"; 
    } 

    return $names; 
} 

function expand_filenames($input) 
{ 
    $nbBrackets = substr_count($input, '('); 

    // Start with the last pair. 
    $sets = expand_bracket_pair($input); 

    // Now work backwards and recurse for each generated filename set. 
    for ($i = 0; $i < $nbBrackets; $i++) 
    { 
     foreach ($sets as $k => $set) 
     { 
      $sets = array_merge(
       $sets, 
       expand_bracket_pair($set) 
      ); 
     } 
    } 

    // Clean up. 
    foreach ($sets as $k => $set) 
    { 
     if (false !== strpos($set, '(')) 
     { 
      unset($sets[$k]); 
     } 
    } 
    $sets = array_unique($sets); 
    sort($sets); 

    return $sets; 
} 

var_dump(expand_filenames('/(a|b)/var/(www|www2)/index.(htm|html|php|shtml)')); 
+0

Bardzo dobra robota - Kudos dla ciebie. * Ale * nie może zajmować się wieloma parami wsporników, tak jak ja * nie * wspomina w moim pytaniu - poprawię to od razu - ale * zrobiłem * w moim wyzwaniu dla ciebie. :) Myślę, że takie podejście jest trudne do rozszerzenia, więc może poradzić sobie z wieloma parami wsporników. Czy jestem w błędzie? –

+0

Okay, jestem przekonany. Podzielę pary wielokrotnych nawiasów za pomocą prostego wyrażenia regularnego, a następnie uruchom na nich swoją funkcję. Działa to zbyt ładnie, aby nie używać :) –

+0

Czy wiele par nawiasów oznacza jak '(html | php (4 | 5))'? Nie jestem pewien, czy rozumiem, ale zaktualizuję kod, jeśli możesz to potwierdzić. Kod obecnie pasuje tylko do ostatniej pary nawiasów. –

4

Nie dokładnie, o co prosicie, ale co z sobą tylko to, co masz, aby otrzymać listę (ignorując | s), wprowadzenie go do zmiennej, a następnie explode ing na przycisk | s? To dałoby ci zestaw wielu różnych przedmiotów (w tym 1 jeśli nie było prezentu).

+0

To prawda, dobry punkt. Próbuję to teraz. –

5

myślę szukasz:

/(([^ |] +) (| ([^ |] +)) +)/

Zasadniczo umieścić rozdzielacz '|' w powtarzalny wzór.

Również twoje słowa powinny być uzupełniane "nie rurami" zamiast "nie parenami", zgodnie z trzecim wymaganiem.

Ponadto, wolę od + do * ten problem. + oznacza "co najmniej jeden".* oznacza "zero lub więcej".

+0

Pozdrowienia @CWF, to jest dokładnie to, o co prosiłem. Skończyły się głosy na dzisiaj, w przeciwnym razie dałbym +1. Zajmę się tym jeszcze jutro, nie jestem jeszcze pewien, jak zbudować ciągi zmian, może potrzebuję preg_match_callback - spróbuję. W każdym razie, bardzo dziękuję za powtarzalny schemat. –

2

Może jestem wciąż nie pytanie, ale moje założenie jest używasz przy pomocy systemu plików, aż trafisz jeden z plików, w którym to przypadku może do

$files = glob("$path/index.{htm,html,php,shtml}", GLOB_BRACE); 

Wynikowa tablica będzie zawierać dowolny plik pasujący do twoich rozszerzeń w ścieżce $ lub żaden. Jeśli chcesz dołączyć pliki według określonego zamówienia rozszerzenia, możesz foreach nad tablicą z uporządkowaną listą rozszerzeń, np.

foreach(array('htm','html','php','shtml') as $ext) { 
    foreach($files as $file) { 
     if(pathinfo($file, PATHINFO_EXTENSION) === $ext) { 
      // do something 
     } 
    } 
} 

Edit: i tak, można mieć wiele nawiasów klamrowych w glob.

+0

To było * to * łatwe. Dzięki Gordon. Nie miałem pojęcia, że ​​Glob może robić takie rzeczy. Nie mogę z czystym sumieniem odeprzeć podanej odpowiedzi, ponieważ pytałem konkretnie, jak przeanalizować ciąg znaków, ale umieszczę notatkę o twojej odpowiedzi na pytanie. –

+0

W celu uzyskania dalszych informacji, więcej informacji na temat 'GLOB_BRACE', z przykładami, tutaj: http://de.php.net/manual/en/function.glob.php#88250 –

+0

Drobne zastrzeżenie:' GLOB_BRACE' nie jest dostępne w niektórych nie systemy GNU, w tym Solaris (ale jest obsługiwany w systemie Windows). Spróbuję dowiedzieć się, które dokładnie http://stackoverflow.com/questions/2536924/glob-brace-portability –

1

Odpowiedź jest podana, ale jest to zabawne puzzle i po prostu nie mógł się oprzeć

function expand_filenames2($str) { 
    $r = array($str); 
    $n = 0; 
    while(preg_match('~(.*?) \((\w+ \| [\w|]+) \) (.*) ~x', $r[$n++], $m)) { 
     foreach(explode('|', $m[2]) as $e) 
      $r[] = $m[1] . $e . $m[3]; 
    } 
    return array_slice($r, $n - 1); 
} 



print_r(expand_filenames2('/(a|b)/var/(ignore)/(www|www2)/index.(htm|html|php|shtml)!')); 

może to wyjaśnia trochę dlaczego lubimy wyrażeniach regularnych tyle;)

+0

@stereofrog sweet !!! +1. –

+0

@stereofrog jednak, '\ w' musiałby zostać rozszerzony do czegoś takiego jak' \ w \ d', aby dopasować dowolną wyobrażalną (standardową) nazwę pliku. –