Aprendamos sobre Expresiones regulares

Hoy toca un poco de expresiones regulares.

Primero deberíamos saber que funciones utilizan dichas expresiones.

Todas las que empiezan por 'preg' como son:

preg_filter
preg_grep
preg_last_error
preg_match_all
preg_match
preg_quote
preg_replace_callback
preg_replace
preg_split

Estas son todas las funciones y podéis encontrar su explicación
En el paper de PCRE de php.net http://es2.php.net/manual/en/book.pcre.php

Cómo funcionan las expresiones regulares?

Bien, básicamente lo que hacemos es dar un Pattern (o patrón) y a partir
de este buscamos coincidencias.

Cabe destacar que cuando damos el patrón 'am' lo que buscamos es cualquier palabra
que contenga 'am' y no la palabra 'am' en sí.
Siendo validos: am, amanecer, mama, entre otros...


Caracteres de las expresiones regulares:

Tenemos varios caracteres con funciones especiales

\ - Carácter de escape. Escapa un carácter especial.
^ - Inicio de cadena. Indica que el patrón especificado a continuación va al inicio
siguiendo el ejemplo anterior '^am' siendo válidos solo: am y amanecer
$ - Fin de cadena. Exactamente lo mismo que el anterior pero al final
. - Representa cualquier carácter, pero solo uno. Con el patrón c.d
podemos pensar como válidos: cad, cod,cud,clda, code pero no caac o ccld por ejemplo
[ - Inicio de definición de clase de caracteres
] - Fin de la definición anterior
| - Operador lógico OR. si tenemos: v|a podemos dar como válidos v o a por ejemplo
* - Cuantificador de cero o más. Con el ejemplo: "a*" podemos pensar en 'a' o 'aa' o 'abb'
+ - Cuantificador de uno o más. Igual que el anterior pero no será válido 'a'
{ - Inicio de valores mínimo máximo
} - Fin de valores mínimo máximo
? - Puede servir de cuantificador, modificador de codicia y para definir clases especiales.


Ahora vamos a tratar de hablar de ellos un poco más a fondo.

Carácter de escape

Si tenemos uno de los caracteres mencionados anterior, por ejemplo ^, pero no queremos
que este ejerza su función sino que sea un carácter más usaremos el carácter de escape.

Ejemplo:

Patrón: "\^Hola!"
Válido: ^Hola!!, C^Hola!, etc
No válido: "Hola!", "^Hol!"

Según e leído (y aún no he comprobado) si PHP encuentra un carácter de escape y su siguiente
no es un carácter de la lista toma el carácter de escape como carácter normal

Por lo que: "\(" y "\\(" Representan lo mismo: "\("

Hay algunos caracteres que no están en la lista anterior y son caracteres de escape:

\n - Salto de línia
\r - Retorno de carro
\t - tabulación
\xhh - Hexadecimal, hh son números en hexadecimal
\ddd - Octal.

También disponemos de otros caracteres de escape dentro de las expresiones regulares:

\d - Cualquier digito decimal, 0-9 y los superíndices
\D - Digitos no decimales (todos los que no son los anteriores)
\s - Caracteres espaciadores: ' ', '\n', '\t', '\r'
\S - Caracteres no espaciadores
\w - Carácter alfanumérico o '_'
\W - Caracteres no alfanuméricos ni '_'
\a - Carácter de inicio de cadena. Equivale a ^
\A - Inicio de línea. Todo carácter que inicia una línea
\z - Carácter de fin de cadena. Equivale a $
\Z - Todo carácter que finaliza una línea

Las clases de caracteres

Para refrescar un poco las clases de caracteres son las que están entre [ y ]

Dentro de estas clases no funcionan todo lo expuesto anteriormente. Estos si funcionan:

\ - Carácter de escape
- - Definir rango de caracteres. Ejemplo: [a-z] define de la a la z
^ - Es un carácter de expulsión, con esto quitamos aquellos que no queremos en la clase
Ejemplo: [a-z^dbg], son todos los caracteres de la a a la z menos dbg.

Nota: Recordamos que esto se rige por los códigos ASCII por lo que no es lo mismo a que A

Para estos tres es necesario escaparlos para usarlos, pero no los de la lista del principio
Por lo que $ o + son perfectamente funcionales sin escaparlos.

La segunda lista proporcionada en "caracteres de escape" es reutilizable en esta
sección, por lo que podemos hacer cosas como: "[\w^_]+"

Subpatrones

Los subpatrones se delimitan con paréntesis y pueden estar concatenados.

Encontramos dos utilidades principales:

- Agrupaciones para usar el OR:

Ejemplo:
Pattern: "per(sona|ro)"
Coincide: tanto con persona como con perro

- Capturar fragmentos que luego utilizaremos

Esta me he planteado no presentarla por lo complicado que puede ser entenderla al
principio, así que si os la queréis saltar no hay problema.

Supongamos que queremos encontrar todo lo que esté encerrado entre ":

Patrón: "\"+\"" (PHP necesita que escapemos las comillas.

Ahora supongamos que también queremos que detecte las comillas simples:

Patrón: "(\"|\')+(\"|\')"
Pero esta expresión no es del todo correcta, puede darse el caso de capturar: " "hola' "

Lo cual no tiene sentido. Entonces podríamos pensar:

Patrón "\"+\"|\'+\'"
Pero imaginemos que también capturamos caracteres entre #, /*, etc...

Entonces lo mejor es:
Patrón "(\"|\'|\#|...)+\1"

Los ... referencian a los demás subpatrones que podríamos agregar.
Destaco el \1 es una "referencia anterior" y hace referencia al primer subpatrón,
el \2 haría referencia al segundo, etc..

De forma vulgar sería como hacer: "(\"|\'|\#|...)+(\"|\'|\#|...)"

solo que no se producen casos como " "Hola' ". Es decir, una maravilla.

Cuantificación

Funciona de la siguiente manera:

"X{min,max}" X representa un carácter, una clase de caracteres o subpatron y min y max
representan el número de veces mínimo y máximo que aparece X.

Ejemplo:
Patrón: "\w{2,4}"
Este patrón nos indicaría palabras de dos a cuatro letras.

Si se omite 'max', se entiende que X se repite 'min' o más veces

Ejemplo:
Patrón: "\w{2,}"
Dos letras o más, NO ONITIR LA COMA!

Si omitimos la coma significa que se repite ese número exacto.

Ejemplo:
Patrón: "\w{10}"
Palabras de 10 letras exactas.

Tenemos a nuestra disposición otros cuantificadores, pero se pueden crear con el método
normal, de todas formas los menciono:

X* equivale a X{0,}
X+ equivale a X{1,}
X? equivale a X{0,1}

Codicia

Usando el ejemplo de los subpatrones "(\"|\')+\1" podremos explicar que significa exactamente
la codicia.

Las expresiones regulares son codiciosas, es decir intentarán coincidir el mayor número posible.

Ejemplo:
Patrón: "(\"|\')+\1"
Cadena: "a href='index.php' target='_self'>"
Coincidirá: "'index.php' target='_self'"

Como podéis notar toma desde la primera comilla simple hasta la última, para evitar
este suceso se puede evitar enredando un poco más la expresión:

Ejemplo:
Patrón "(\"|\')[^\1]+\1"

Con este ejemplo lo que le decimos es que el carácter capturado en el subpatron no puede
estar dentro de la cadena resultado

Por lo que la coincidencia será: 'index.php'


Con esto acabamos una clase básica de expresiones regulares.

Hay algunas cosillas más pero esto es lo más frecuente
No es nada difícil, sino que hay que echarle ganas y repasar dos o tres veces los ejemplos
y crear unos propios.

Basado en la información de:
php-hispano.net
php.net