2010-03-28 22 views
6

que quiero ser capaz de analizar las rutas de archivos como éste:de expresiones regulares para que coincida con un número ilimitado de opciones

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

en una matriz ordenada:

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

y luego producir una lista de alternativas :

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

en este momento, tiene declaración preg_match que puede dividir dos alternativas:

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

Podría alguien darme un puntero cómo extender esto a aceptar una ilimitado número de alternativas (al menos dos)? Solo con respecto a la expresión regular, el resto puedo tratarlo.

La regla es:

  • La lista debe comenzar con una ( y cerrar con un )

  • Debe haber un | en la lista (es decir, al menos dos alternativas)

  • Cualquier otra aparición (es) de ( o ) deben permanecer intactas.

Actualización: tengo que ser capaz de tratar también con múltiples pares de soportes tales como:

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

lo siento, no he dicho eso de inmediato.

Actualización 2: Si usted está buscando para hacer lo que estoy tratando de hacer en el sistema de archivos, a continuación, señalar que glob() ya trae esta funcionalidad fuera de la caja. No hay necesidad de implementar una solución personalizada. Ver la respuesta de @ Gordon a continuación para más detalles.

+1

¿Por qué diablos está todo el mundo * * obsesionado ** con expresiones regulares? Solo usa un maldito método diferente. Coincidir todo después de un corchete ** no es difícil ** sin expresiones regulares. –

+0

@Coronatus muéstrame un método elegante, liviano y no regex que puede 1. lidiar con múltiples pares de corchetes y 2. ignorar cualquier par de corchetes que no contenga '|', y no se ve como una mierda, y yo ' Con gusto te llamaré mi sombrero. –

+1

Hecho. Ver mi respuesta –

Respuesta

3

solución para no expresiones regulares :)

<?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

Muy buen trabajo - Felicitaciones para ti. * Pero * no puede tratar con múltiples pares de corchetes como yo * no * mencioné en mi pregunta - Lo corregiré enseguida - pero * lo hice * en mi desafío. :) Creo que este enfoque es difícil de extender, por lo que puede tratar con múltiples pares de corchetes. ¿O estoy equivocado? –

+0

De acuerdo, estoy convencido. Dividiré los pares de paréntesis múltiples usando una expresión regular simple, y luego ejecutaré su función en ellos. Esto funciona muy bien como para no usar :) –

+0

¿Significan varios pares de paréntesis como '(html | php (4 | 5))'? No estoy seguro de entender pero actualizaré el código si puede confirmarlo. El código actualmente solo coincide con el último par de corchetes. –

4

No es exactamente lo que están pidiendo, pero lo que es malo con sólo tomar lo que usted tiene que conseguir la lista (haciendo caso omiso de la | s), poniéndolo en una variable y luego explode ing en las | s? Eso le daría una variedad de todos los artículos que haya (incluso 1 si no hubiera un regalo).

+0

Verdadero, buen punto. Probando eso ahora. –

5

Creo que está buscando:

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

Básicamente, poner el divisor '|' en un patrón de repetición.

Además, sus palabras deben estar formadas por "no tubos" en lugar de "no parens", según su tercer requisito.

También, prefiera + a + para * para este problema. + significa 'al menos uno'.* significa 'cero o más'.

+0

Cheers @CWF, esto es exactamente lo que pedí. Me he quedado sin votos para hoy, de lo contrario hubiera +1. Voy a analizar esto un poco más mañana, todavía no estoy seguro de cómo construir las cadenas de variación, puedo necesitar un preg_match_callback - lo intentaré. De todos modos, muchas gracias por el patrón de repetición. –

2

Tal vez todavía no recibo la pregunta, pero mi suposición es que se están ejecutando a través del sistema de archivos hasta llegar a uno de los archivos, en cuyo caso se podría do

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

La matriz resultante contendrá cualquier archivo que coincida con sus extensiones en $ path o none. Si necesita incluir archivos por una orden de extensión específica, puede foreach en la matriz con una lista ordenada de extensiones, p.

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

Editar: y sí, puede tener varias llaves en pegote.

+0

Fue * que * fácil. Gracias Gordon. No tenía idea de que Glob pudiera hacer tales cosas. No puedo, con buena conciencia, no aceptar la respuesta dada, ya que estaba preguntando específicamente cómo analizar la cadena, pero pondré una nota sobre tu respuesta en la pregunta. –

+0

Para referencia futura, más información sobre 'GLOB_BRACE', con ejemplos, aquí: http://de.php.net/manual/en/function.glob.php#88250 –

+0

Advertencia menor:' GLOB_BRACE' no está disponible en algunos sistemas no GNU, incluido Solaris (pero es compatible con Windows). Trataré de averiguar cuáles exactamente http://stackoverflow.com/questions/2536924/glob-brace-portability –

1

La respuesta se da, pero es un rompecabezas divertido y simplemente no pude resistir

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)!')); 

tal vez esto explica un poco por qué nos gusta expresiones regulares que mucho;)

+0

@stereofrog sweet !!! +1. –

+0

@stereofrog, sin embargo, el '\ w' debería expandirse a algo como' \ w \ d' para que coincida con cualquier nombre de archivo concebible (estándar). –

Cuestiones relacionadas