El Codiguero
Programando para la wé

Avatar de alvlin Publicado por alvlin, el 23/12/2008
Categorías: PHP, Programación

Expresiones regulares con PHP - Perl

Nota: Como texto a analizar se utilizará esta página, que es un trozo conveniente de esta otra. Se eligió este texto por ser repetitivo y sencillo de comprender. Para analizarlo, se utilizará el siguiente patrón:
([0-9]{4}) ([A-Za-z]+) ([0-9]{2}): <a href="([^"]+)">(.*?)</a><br>

Introducción

PHP incluye soporte para expresiones regulares en el núcleo mismo del lenguaje, no se requieren extensiones para habilitarlo. Se soporta por defecto tanto la sintaxis POSIX (funciones ereg*) como la sintaxis PERL (funciones preg*).

Tradicionalmente se prefiere el uso de la sintaxis de Perl, en el entendido de que las funciones correspondientes tienen un mejor rendimiento que sus homólogas POSIX; sin embargo esto varía caso a caso según el tipo de patrón que se utilice. Si el rendimiento es crítico, se deben probar ambos tipos de patrones y comparar sus resultados.

Como mencionaba en una parte anterior de esta serie (Tipos de coincidencias y referencias), las funciones de expresiones regulares se separan en tres grupos: coincidencia de texto, reemplazo de texto, y separación de cadenas; siendo esta última la opción menos usada.

Funciones PCRE

Las funciones que PHP provee para utilizar expresiones regulares con sintaxis Perl son:

El listado completo de funciones se puede ver en http://www.php.net/manual/es/ref.pcre.php.

Los modificadores que provee la biblioteca PCRE (que PHP usa para soportar la sintaxis Perl) se describen en la página del manual de Modificadores de Patrón. Dada la existencia del modificador i, no existen funciones diferentes para realizar una comparación sensible a mayúsculas y minúsculas, como en el caso de las funciones POSIX.

Coincidencia de texto

Para buscar texto en una cadena se utilizan las funciones preg_match y preg_match_all.
La diferencia entre ambas es que preg_match detiene la búsqueda al encontrar la primera coincidencia, comportándose igual que ereg. La función preg_match_all, por otro lado, captura todas las coincidencias.

La sintaxis de preg_match es:
int preg_match ( string $patron , string $texto_en_el_que_buscar [, array &$coincidencias [, int $banderas [, int $desplazamiento ]]] )

Dejaremos de lado los parámetros $banderas y $desplazamiento, que normalmente no se utilizan. El valor retornado por la función es 1 si se encontró una coincidencia, 0 en caso contrario. En caso de que el patrón contenga paréntesis, los datos se capturarán en el vector $coincidencias, de forma tal que el trozo de la cadena que coincide con el patrón se guarda en el índice cero, el trozo capturado por el primer juego de paréntesis se guardará en el índice 1, el trozo capturado por el segundo juego se guardará en el índice 2, y así sucesivamente.

Ejemplo

He aquí un ejemplo de uso:

<?php define('ARCHIVO', 'ejemplo.txt'); define('PATRON', '#([0-9]{4}) ([A-Za-z]+) ([0-9]{2}): <a href="(.+)">(.*)</a><br>#U'); $archivo = file_get_contents( ARCHIVO ); $res = preg_match( PATRON, $archivo, $partes ); if ($res !== 0) { print_r($partes); }

Este código carga el contenido del archivo y le aplica el patrón. El resultado será el siguiente:

Array ( [0] => 2008 November 16: <a href="ap081116.html">Anticrepuscular Rays Over Colorado</a><br> [1] => 2008 [2] => November [3] => 16 [4] => ap081116.html [5] => Anticrepuscular Rays Over Colorado )

Como puede verse, el índice cero del vector contiene la coincidencia completa, es decir, todo el texto que coincidió con el patrón. A partir del índice 1, se almacenan los trozos de texto que coincidieron con cada juego de paréntesis en el patrón.

El problema con esta función es que solamente captura la primera coincidencia. Por esto, en vez de devolver todos los enlaces del archivo, la salida de el código anterior contiene solamente la primera coincidencia, y no todas. Para capturar todas las coincidencias del patrón sobre un texto, se utiliza la función preg_match_all)

Ejemplo 2: preg_match_all

El código necesario para utilizar esta función es exactamente igual al requerido para utilizar preg_match, solamente cambia el nombre de la función.
<?php define('ARCHIVO', 'ejemplo.txt'); define('PATRON', '#([0-9]{4}) ([A-Za-z]+) ([0-9]{2}): <a href="(.+)">(.*)</a><br>#U'); $archivo = file_get_contents( ARCHIVO ); $res = preg_match( PATRON, $archivo, $partes ); if ($res !== 0) { print_r($partes); }

Esta vez el resultado es bastante más extenso (aunque aquí aparece resumido):

Array ( [0] => Array ( [0] => 2008 November 16: <a href="ap081116.html">Anticrepuscular Rays Over Colorado</a><br> [1] => 2008 November 15: <a href="ap081115.html">Arp 273</a><br> [2] => 2008 November 14: <a href="ap081114.html">Fomalhaut b</a><br> [3] => 2008 November 13: <a href="ap081113.html">A Bubble in Cygnus</a><br> [4] => 2008 November 12: <a href="ap081112.html">Phoenix and the Holy Cow</a><br> [5] => 2008 November 11: <a href="ap081111.html">The Cosmic Web of the Tarantula Nebula</a><br> [6] => 2008 November 10: <a href="ap081110.html">Our Galaxy's Central Molecular Zone</a><br> [7] => 2008 November 09: <a href="ap081109.html">Two Black Holes Dancing in 3C 75</a><br> [8] => 2008 November 08: <a href="ap081108.html">On the Trail of 2008 TC3</a><br> [9] => 2008 November 07: <a href="ap081107.html">Cygnus Trio</a><br> [10] => 2008 November 06: <a href="ap081106.html">A Sharper View of a Hazy Giant</a><br> [11] => 2008 November 05: <a href="ap081105.html">Seventeen Hundred Kilometers Above Enceladus</a><br> [12] => 2008 November 04: <a href="ap081104.html">The Double Ring Galaxies of Arp 147 from Hubble</a><br> [13] => 2008 November 03: <a href="ap081103.html">A Spectacular Rayed Crater on Mercury</a><br> [14] => 2008 November 02: <a href="ap081102.html">Spicules: Jets on the Sun</a><br> [15] => 2008 November 01: <a href="ap081101.html">A Spectre in the Eastern Veil</a><br> ) [1] => Array ( [0] => 2008 [...] [15] => 2008 ) [2] => Array ( [0] => November [...] [15] => November ) [3] => Array ( [0] => 16 [...] [15] => 01 ) [4] => Array ( [0] => ap081116.html [...] [15] => ap081101.html ) [5] => Array ( [0] => Anticrepuscular Rays Over Colorado [...] [15] => A Spectre in the Eastern Veil ) )

La salida de esta función es un tanto extraña. Uno esperaría recibir una matriz bidimensional en la que cada entrada fuera una coincidencia, y dentro de ella encontrar una entrada por cada trozo capturado, algo así:

Array ( [0] => Array ( [0] => 2008 November 16: <a href="ap081116.html">Anticrepuscular Rays Over Colorado</a><br> [1] => 2008 [2] => November [3] => 16 [4] => ap081116.html [5] => Anticrepuscular Rays Over Colorado ) )

Sin embargo, lo que se devuelve es una matriz en la que la n-ésima entrada contiene cada trozo capturado por el n-ésimo paréntesis, de tal forma que si el nombre de la matriz es $resultados, $resultados[$n][$m] contiene el trozo de la m-ésima coincidencia que fue capturado por el n-ésimo paréntesis.

Reemplazo de texto

El reemplazo de texto se logra con preg_replace. Se puede hacer uso de las referencias para vincular al contenido capturado por los paréntesis.

Por ejemplo, puede sustituirse el enlace por un listado del día y el título:

(.+)</a>#U'); $archivo = file_get_contents( ARCHIVO ); $res = preg_replace( PATRON, 'Imagen del día \\3 de \\2: \\5', $archivo ); echo $res;

Imagen del día 16 de November: Anticrepuscular Rays Over Colorado Imagen del día 15 de November: Arp 273 Imagen del día 14 de November: Fomalhaut b Imagen del día 13 de November: A Bubble in Cygnus Imagen del día 12 de November: Phoenix and the Holy Cow Imagen del día 11 de November: The Cosmic Web of the Tarantula Nebula Imagen del día 10 de November: Our Galaxy's Central Molecular Zone Imagen del día 09 de November: Two Black Holes Dancing in 3C 75 Imagen del día 08 de November: On the Trail of 2008 TC3 Imagen del día 07 de November: Cygnus Trio Imagen del día 06 de November: A Sharper View of a Hazy Giant Imagen del día 05 de November: Seventeen Hundred Kilometers Above Enceladus Imagen del día 04 de November: The Double Ring Galaxies of Arp 147 from Hubble Imagen del día 03 de November: A Spectacular Rayed Crater on Mercury Imagen del día 02 de November: Spicules: Jets on the Sun Imagen del día 01 de November: A Spectre in the Eastern Veil

División de cadenas

Para dividir cadenas PHP incluye la función explode(), que divide una cadena en trozos utilizando otra cadena (que se le pasa como parámetro) como separador.
El problema con explode es que toma una cadena fija, por lo que en ocasiones puede no tener la flexibilidad necesaria.

La función preg_split() funciona de forma similar a explode, pero en vez de utilizar una cadena fija como separador utiliza una expresión regular.

Cualquiera que haya utilizado la función explode sabe cómo se utiliza preg_split, ya que ambas se utilizan de forma similar. Recomiendo ver las páginas del manual de ambas funciones para obtener ejemplos de uso.

  • Digg
  • del.icio.us
  • Meneame
  • Reddit
  • Technorati
  • StumbleUpon
  • Facebook
  • LinkedIn
  • MySpace
  • Yahoo! Buzz
  • YahooMyWeb

» Si te pareció interesante, dejá un comentario...



Todo el contenido de este sitio está bajo una licencia de Creative Commons.

Campaña AnyBrowser | XHTML 1.0 Válido | CSS 2 Válido | WAI A

Diseño creado por alvlin. Sitio basado en WordPress