2009-03-29 9 views
13

Estoy tratando de hacer coincidir una cadena que puede aparecer en varias líneas. Comienza y termina con una cadena específica:Incluyendo nuevas líneas en la función PHP preg_replace

{a}some string 
can be multiple lines 
{/a} 

¿Puedo agarrar todo lo que entre {a} y {/a} con una expresión regular? Parece el. no coincide con nuevas líneas, pero he intentado lo siguiente sin suerte:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/', 'X', $template, -1, $count); 
echo $count; // prints 0 

Coincide. o \ n cuando están solos, ¡pero no juntos!

Respuesta

31

Uso del s modifier:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count); 
//            ^
echo $count; 
+0

¡Impresionante, sabía que sería algo así de simple! – DisgruntledGoat

+0

Además, descubrí que esta información se encuentra en el sitio web de PHP, aunque nunca la encontré antes cuando busco ... http://www.php.net/manual/en/reference.pcre.pattern.modifiers .php – DisgruntledGoat

3

De http://www.regular-expressions.info/dot.html:

"El punto detecta un solo carácter, sin importar lo que el carácter es La única excepción son de nueva línea caracteres."

tendrá que agregar un trailing/s bandera a su expresión.

6

Creo que tienes más problemas que solo el punto que no coincide con las nuevas líneas, pero déjame comenzar con una recomendación de formato. Puedes usar casi cualquier caracter de puntuación como el delimitador de expresiones regulares, no solo la barra inclinada ('/'). Si usa otro personaje, no tendrá que escapar de las barras dentro de la expresión regular. Entiendo que '%' es popular entre los PHPers; que haría que su argumento patrón:

'%\{a\}([.\n]+)\{/a\}%' 

Ahora, la razón por la que la expresión regular no funcionó como se pretendía se debe a que el punto pierde su significado especial cuando aparece dentro de una clase de caracteres (los corchetes) - por lo [.\n] solo coincide con un punto o un salto de línea. Lo que estábamos buscando era (?:.|\n), pero me han recomendado que coincide con el retorno de carro, así como el avance de línea:

'%\{a\}((?:.|[\r\n])+)\{/a\}%' 

Eso es debido a que la palabra "nueva línea" puede referirse al estilo Unix "\ n", Estilo de Windows "\ r \ n", o estilo Mac anterior "\ r". Cualquier página web dada puede contener cualquiera de esos o una mezcla de dos o más estilos; una mezcla de "\ n" y "\ r \ n" es muy común. Pero con el modo/s (también conocida como una sola línea o modo dotall), no es necesario que preocuparse de que:

'%\{a\}(.+)\{/a\}%s' 

Sin embargo, hay otro problema con la expresión regular original que todavía está presente en éste: el + es codicioso. Eso significa que, si hay más de una secuencia de {a}...{/a} en el texto, la primera vez que se aplica su expresión regular corresponderá a todas, desde la primera {a} hasta la última {/a}. La forma más sencilla de arreglar eso es hacer que el + ungreedy (también conocido como "perezoso" o "reacios") añadiendo un signo de interrogación:

'%\{a\}(.+?)\{/a\}%s' 

Por último, no sé qué hacer con el '$ 'antes de la cita de apertura de su argumento de patrón. No hago PHP, pero eso me parece un error de sintaxis. Si alguien pudiera educarme en este asunto, lo agradecería.

+0

Oh, eso debe ser un error tipográfico: originalmente estaba usando una variable y la reemplacé con una cadena para este ejemplo. – DisgruntledGoat

+0

Esta fue una gran explicación. Saludos por esto. – craignewkirk