Ver Mensaje Individual
  #24 (permalink)  
Antiguo 19/08/2003, 23:36
leonardop
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola de nuevo,

Me alegra que gracias a Manoloweb ya hayas encontrado la solución a tu último problema.

Por otra parte, ciertamente me parece importante que cosas como el significado de ciertas expresiones regulares resulte bien claro, en especial cuando, como ocurre en este caso, recae sobre una sola expresión regular gran parte de la funcionalidad de un algoritmo. Está muy bien que preguntes si no te ha quedado claro algo. Aquí todos estamos aprendiendo.

(Mientras escribía esta respuesta ya nuestro amigo aclaró brevemente el significado de la expresión, así que las siguientes líneas vendrían a repetir varias cosas, pero enviaré su contenido completo al menos por no alterar su sentido lógico.)

Las expresiones regulares son un tema extenso por sí solo, y de hecho existen libros enteros dedicados a su tratamiento. Uno de los principales problemas cuando se trata de implementar expresiones regulares es, por ejemplo, que no suele haber un consenso uniforme sobre el formato particular de las expresiones regulares. Distintas aplicaciones pueden contar con diferentes implementaciones para distintos tipos de expresiones regulares.

Por ejemplo, PHP mismo viene en la actualidad con soporte para dos tipos de estilos diferentes de expresiones regulares: estilo `Perl' y estilo `POSIX'. El estilo Perl, como es de suponerse, que busca ser tan fiel como sea posible al modo en que las expresiones regulares son tratadas en el lenguaje de programación Perl. Y el estilo POSIX, que opera bajo una seria de reglas definidas en un documento preparado por un comité que busca la estandarización de normas y reglas semánticas en ésta y otras áreas afines a los sistemas computacionales. Por encima, podría pensarse que no hay muchas diferencias entre uno u otro estilo, pero a medida que se entra en los detalles de la implementación (cosa que se aprecia inmediatamente en la medida en que se construyen expresiones regulares cada vez más sofisticadas), es inevitable toparse con diferencias críticas entre los dos estilos.

En fin, en PHP, las funciones de la `familia' preg_*() (preg_match(), preg_match_all(), preg_replace(), etc.) son parte del grupo de funciones de expresiones regulares compatibles con Perl. La documentación de PHP contiene extensiva información al respecto. Personalmente me parece especialmente valiosa para quien esté aprendiendo sobre expresiones regulares la página sobre Sintaxis de los patrones. Así mismo, y ya que hablamos de expresiones regulares "estilo Perl", cabría mencionar que la documentación de éste lenguaje al respecto es también muy informativa y extensa.

Entrando a referirnos particularmente sobre la expresión regular de nuestro ejemplo, podríamos describir su significado más o menos de esta forma:


Arrancamos de la siguiente expresión original

'/\\b[\\d\\.]+\\b/'

Antes que nada, cabe mencionar que esta expresión resulta siendo almacenada como algo de esta forma:

/\b[\d\.]+\b/

Pudo haberse escrito sin escapar algunos caracteres desde un principio, pero no se pierde nada al colocar las barras invertidas de forma explícita :) --escapar se le llama a la acción de preceder un caracter dado con una barra invertida (\), usualmente dentro de secuencias que contienen caracteres especiales.

Ahora bien, veamos el significado de cada segmento de la expresión regular:
  • Los caracteres delimitadores: //. Son aquellas barras que se encuentran al comienzo y al final de la expresión regular (claro que podrían ser otros caracteres diferentes a las barras). El uso de estos delimitadores nos permiten, por ejemplo, especificar modificadores especiales por fuera de la expresión regular misma. En este ejemplo no se usa ningún modificador, de modo que baste decir que los delimitadores solo son esos caracteres ubicados al principio y al final de la expresión.
  • Los indicadores de `límite' (boundaries): `\b'. Estos caracteres indican que, en el punto específico de la expresión en donde hayan sido colocados, debe existir un "límite" dentro de la secuencia de caracteres dada. Un límite puede ser el comienzo o final de la cadena (si el primer/último caracter es una letra tipo `palabra'), así como puede ser el paso de un caracter tipo `palabra' a un caracter `no-palabra'. Los caracteres `palabra' (\w) consisten en el rango de letras (mayúsculas y minúsculas), los números (0-9) y la raya inferior (_). Un caracter `no-palabra' (\W) es cualquier cosa diferente a \w.

    Por ejemplo, consideremos la frase "Todos los dias sale el sol.". Si colocamos un caracter (digamos, un signo de exclamación) en cada punto de esta frase que es considerada un límite, obtendríamos "!Todos! !los! !dias! !sale! !el! !sol!."

    En nuestra ejemplo particular, nuestra expresión regular funcionaría igualmente bien sin las secuencias \b, debido al efecto que tiene que las expresiones regulares sean por defecto "ambiciosas" (greedy), pero no es necesario, por ahora, entrar en detalles. Vamos aprendiendo paso por paso... :)
  • Los símbolos de ``clase de caracter'': []. Los corchetes cuadrados sirven para agrupar un conjunto (o `clase') de caracteres que funcionan como una especie de comodines en un punto determinado de la expresión regular. Básicamente, en nuestro ejemplo, estamos diciendo algo como "Cualquier cosa que sea o `\d' o `\.'".
  • La secuencia de dígito: \d. Esta secuencia produce coincidencias con cualquier cosa que sea un dígito (0-9).
  • El punto simplemente quiere decir eso, "un punto". Está escapado (tiene la barra invertida antes) porque de lo contrario el punto sería interpretado en la expresión regular de forma especial.
  • El más: +. Este caracter significa que aquello que esté ubicado antes de él (un caracter, o una secuencia de caracteres delimitada por paréntesis) debe presentarse una o más veces para generar una coincidencia con la expresión.

Así que, poniendo en palabras la expresión original, sería algo como:

"Busque coincidencias de secuencias de caracteres que, comenzando y terminando en límites (\b), consten de uno o más dígitos o puntos."

Por ejemplo, las siguientes cadenas generan coincidencias:

"Mi abuelo tiene 80 años" --> "80"
"Esta pista mide unos 1.62 kilómetros" --> "1.62"
"3" --> "3"
"abcde12345aeiou" --> "12345"
"." --> "."

Y las siguientes cadenas no generan coincidencias:

"Hoy está lloviendo"
"Yo no fui"


Respecto a las últimas modificaciones hechas por Manoloweb vemos básicamente dos elementos nuevos:
  • Especificación de número de ocurrencias: {}. Los corchetes son usados para especificar la cantidad precisa de veces que un caracter (o secuencia de caracteres delimitada por paréntesis) debe presentarse. Dentro de estos corchetes suelen ir dos valores, usados como límite inferior y límite superior del rango. Por ejemplo, {2,} quiere decir "dos o más veces" (cuando no se ingresa el segundo valor del rango, se asume que no hay límite superior", mientras que {0,1} quiere decir "0 o 1 vez". Cabe anotar que hay otro símbolo que representa exactamente lo mismo que {0,1} y es el signo de interrogación (?).
  • El comodín "cero o más veces": *. Un asterisco es equivalente a {0,}.


Mmm, ahora que la he separado en partes, veo que la expresión regular puede simplificarse un poco. Como ya he dicho, los indicadores de límites sobran, por otra parte, las clases de caracteres no tienen mucho sentido si solo se agrupa un caracter, de modo que los corchetes cuadrados sobran también, y finalmente podría reemplazarse {0,1} con ?.

De modo que la expresión regular podría resultar en algo como:

/\\d{2,}\\.?\\d*/


Bueno, te deseo mucha suerte, y espero que puedas dedicarle un poco de tiempo al estudio de expresiones regulares, son un recurso valiosísimo, y entretenido... :)

Un cordial saludo