Tutotial de Perl

Tabla de contenidos
Seccion 3.4- Expresiones Regulares


3.4.1- Símbolos Normales


3.4.1.1- Individuales


3.4.1.2- Genéricos


3.4.2- Símbolos Especiales


3.4.3- Uso de Expresiones regulares

.

3.4.3.1- Búsqueda


3.4.3.2- Substitución


3.4.4- Variables


3.4.4.1- Variables de entrada


3.4.4.2- Variables de salida

Version 2.1, Lunes 14 de Abril de 1997

Daniel Sol Llaven


3.4- Expresiones Regulares


Una de las características mas útiles de Perl es el proceso que da a sus escalares. Y las cadenas de caracteres reciven especial atención.
Una de las tareas mas comunes al trabajar con cadenas es el extraer subcadenas o reconocer cadenas de una u otra estructura.
Perl se basa en los conceptos de cadenas regulares para brindar un poderoso manejo de las cadenas de caracteres, para aquellos que no recuerden que son las cadenas regulares, estas son descripciones abstractas de conjuntos de cadenas.
Las definiciones esenciales para las cadenas regulares, ya que una discusión medianamente seria de ellas es materia de estudios mas bien largos; se reducen a:

Símbolo- Es un elemento, único y distinguible de cualquier otro, para Perl son caracteres (especiales y normales) y en lo sucesivo usaremos los términos caracter y símbolo indistintamente,
Cadena Es una serie finita de caracteres.
Lenguaje Es un conjunto de cadenas.
Expresión regular Es la descripción abstracta de un lenguaje, en forma de una cadena.
Lenguaje Regular Es aquel lenguaje que puede ser descrito mediante expresiones regualres.

Aunque esto puede resultar un tanto complejo, la idea central es simple, mediante un conjunto de símbolos describiremos grupos de cadenas, a los que llamamos lenguajes, las descripciones, no son sino series de símbolos, por lo que a fin de cuentas son también cadenas, pero para evitar confusiones les llamaremos expresiones regulares.
Nota: No todos los conjuntos imaginables de cadenas son describibles por lenguajes regualres, de ahí surgen los lenguajes naturales y muchos ortos, pero el estudio de los lenguajes es una rama fascinante pero compleja de la matemática moderna que no trataremos aquí.

A pesar de las promesas de complejidad, el manejo de cadenas regualres lejos de dificultar las cosas, las simplifica sobremanera, aunque suele restar legibilidad al programa, bueno, para contrarrestar esto, recomiendo colocar al menos un comentario por cada expresión regular (de mas de 5 caracteres) que se use.

Los símbolos que en Perl usaremos para construir nuestras expresiones regulares los dividiremos en dos grandes grupos; normales y especiales, los primeros simplemente representaran un caracter mientras que los segundos darán descripciones de cadenas formadas con esos símbolos.

Solo resta recordar que Perl determina las cadenas regualres como aquellas que se encuentran entre "/", de modo que /hola/ Será para Perl una cadena regular. Y a lo largo de este capitulo pondremos las cadenas regulares en el formato de Perl.

3.4.1- Símbolos Normales


3.4.1.1- Individuales

Los símbolos mas usuales para formar parte de nuestras cadenas son los alfabéticos (en mayúsculas y minúsculas) y los dígitos, y estos símbolos se colocan tal cual.

por ejemplo:
/hola/
Esta expresión regular indica que las cadenas así referidas contienen los símbolos "h", "o", "l", y "a" en ese estricto orden.
En matemáticas formales esta expresión daría origen a un lenguaje con una única cadena "hola", pero en Perl, esta expresión regular genera un lenguaje que contiene todas las cadenas que CONTIENEN "hola" en cualquier lugar en su interior. Nótese que Perl no "genera" el lenguaje, pues eso a menudo es una tarea imposible, pero si reconoce a las cadenas que pertenezcan al lenguaje.

Todo caracter que se desee incluir que no sea alfabético, o numérico, deberá anteponerse de un backslash "\" , así por ejemplo:

El lenguaje que reconozca todas las cadenas que contengan "656-31-74.34" se puede representar por la siguiente cadena regular:

/656\-31\-74\.34/

Además, se pueden reconocer, entre otros, los siguientes caracteres especiales:

\sEspacio en blanco
\tTabulador
\nVuelta de carro + Avance de línea
\rVuelta de carro
\0xxCaracter octal xx (i.e. /\062/ para el caracter ASCII 50)
\xXXCaracter Hexadecimal XX (i.e. /\x1B/ para el caracter 27)
\cXCaracter Control+X (i.e. \cC para Ctrl-C)

3.4.1.2- Genéricos

Además, es común que deseemos reconocer una serie de símbolos de algún tipo, entendiendo como tipo de caracter a un conjunto de caracteres, por ejemplo, podemos hablar de los caracteres alfabéticos, que el conjunto de los caracteres de la "a" a la "z" minúsculas y de la "A" a la "Z" (mayúsculas).

Perl define los siguientes grupos de caracteres, además de que con símbolos especiales podemos emplear grupos arbitrarios.

.Cualquier caracter (acepta a cualquiera)
\wCaracter de palabra (alfanumérico y "_")
\WCaracter que no es de palabra (todos menos alfanuméricos o "_")
\dDígito (0 a 9)
\DCaracter que no es Dígito (todos menos 0 al 9)

Además, define como caracteres especiales, las siguientes condiciones (que en realidad no se refieren a ningún caracter).

\bLimite de una palabra
\A ^Principio de cadena (puede usarse indistintamente "^" o "\A"
\Z $Fin de línea

La diferencia entre "\A" y "^" o de "\Z" y "$" es que las versiones con "\" se refieren exclusivamente al inicio o fin de la cadena, y las versiones con un único símbolo se refieren a las diversas líneas dentro de la cadena (si las hay), pero para que estas funcionen de esta forma deberemos usar la opción "/m" e la cadena regular. En casos convencionales son idénticas.

3.4.2- Símbolos Especiales


Además de los símbolos que representan caracteres o series de caracteres tenemos toda una familia de símbolos que representan características de las series de caracteres que ya hemos especificado.

Siendo S un símbolo normal o genérico y E un símbolo especial:
(SS)Agrupa los símbolos
S|SAlternación ( "a" o "b" => /a|b/ )
[S]Clase de caracteres ( puntuación => /[.,;:]/ )
S*Cero, una, dos o cualquier numero de veces
S+Una, dos, o cualquier numero de veces (pero al menos una vez)
S(n)Exactamente n veces (i.e. /a(5)/ Será equivalente a /aaaaa/ )
S(n,m)Al menos n veces y no mas de m veces (i.e. /a(2,4)/ => /(aa)|(aaa)|(aaaa)/ )
S?cero o una vez
SE?Modifica al símbolo especial para que no sea "acaparador"

Estos, como podrá verse, son los mas poderosos ( y menos claros), por lo que a continuación damos una larga lista de ejemplos que emplean uno o varios de ellos.

Palabras:
/\w*/
Son simplemente, todos los caracteres alfanuméricos (y "_") que estén juntos.

Números (naturales)
/\d*/
Es una serie de dígitos simple y sencilla.

Números reales (positivos sin mas adornos)
/\d*\.\d*/
Nótese que el "." necesita ponerse como "\."

Por ejemplo, para reconocer los teléfonos que estén dados en alguno de los formatos:
###-##-## o ###-#### o #####-## o #######, no admitiendo nada antes o después:
/^\d(3)\-?\d(2)\-?d(2)$/
Lo que, en castellano seria:
Inicio de cadena, luego tres dígitos, uno o cero "-", dos dígitos, uno o cero "-", dos dígitos y final de la cadena.

Para reconocer: Nombre Apellido Apellido, dando por hecho que Nombre y los Apellidos son alfabéticos y están separados por espacios:
/\w*\s\w*\s\w*/

Nótese que encontrara al nombre aun si esta dentro de alguna cadena, por ejemplo "674.52.64 Daniel Sol Llaven. Tibet #32" pues la cadena regular descrita si esta presente y no requirió ni inicio ni fin de cadena.
Para encontrar la primera palabra y otra palabra al final, en cualquier cadena:
/^.*?\w*.*?\w*$/
Traducido: Busca el inicio de la cadena, seguido de cualquier numero de caracteres cualesquiera, pero siendo este el mínimo numero que no haga fallar la expresión, seguidos de cualquier numero de caracteres de una palabra, seguidos de otra vez, cualquier numero mínimo de caracteres cualesquiera, seguidos de cualquier numero de caracteres de palabra, seguidos del fin de línea.

No es evidente el que el patrón no realice la operación deseada sin los "? ", para ejemplificarlo, vemos el siguiente ejemplo:
para la cadena: "2342:Esta es la cadena que usamos para probar, si, esta"

con la expresión:
/^.*\w*.*\w*$/
De hecho encuentra la expresión una cadena del lengaje, pero la divide de modo incorrecto (mas adelante veremos como usar las expresiones regualres para extraer segmentos de las cadenas, ahora solo revisemos como se comportan los símbolos especiales).
usemos la siguiente leyenda para indicar a quien asocia cada parte de la cadena regular:

^ inicio de la cadena, no la indicamos.
.* "...." debajo de la parte que es reconocida por estos símbolos.
\w*"11111" debajo de la primera palabra.
.*"****" debajo de la segunda separación
\w*"debajo de la segunda palabra (que esta al final de la cadena).
$ Fin de la línea, no la indicamos.

2342:Esta es la cadena que usamos para probar, si, esta
.....................................................12

Nótese que la primera serie "cualquier caracter de cero a cualquier numero" representada por "." absorbe casi toda la cadena, esto es porque el "*" de la expresión regular es acaparador, y tomara tantos caracteres como le sea posible sin que la expresión no sea reconocida. Se distingue además que no hay una segunda serie de "cualesquiera caracteres" entre las dos palabras, esto es porque el "*" permite desde cero hasta cualquier numero de caracteres, en esta ocasión, toma la opción te adquirir cero caracteres.
Así pues, para que reconozca las palabras como deseamos, debemos hacer que las separaciones no sean acaparadoras, es decir, tomen el mínimo numero de caracteres posible, para que dejen a nuestras palabras los mas posibles. Para lograr esto, ponemos "?" a continuación de los "*" que no deseamos sean acaparadores, resultando la expresión regular:

/^.*?\w*.*?\w*$/

Usando la misma leyenda para ilustrar como reconoce la cadena:

2342:Esta es la cadena que usamos para probar, si, esta
.....1111******************************************2222

Funciono como esperábamos esta vez, porque:
La primera secuencia de "cualesquiera caracteres" toma la mínima cantidad de caracteres que dejan una palabra a continuación (para que la expresión no falle), luego, el "\w*" toma todos los caracteres alfabéticos a su alcance (no hay "_") . La segunda parte ".*? " toma el mínimo de caracteres que dejen a continuación una palabra Y que a continuación de esta palabra este el fin de línea (esta condición del fin de línea evita que termine por ejemplo en el "probar, " pues aunque si es una palabra lo que sigue, no termina en un fin de línea, sino en espacio).

No permita el lector que la aparente complejidad, y patente obscuridad de estas expresiones lo asuste, en el ámbito de la programación real siempre hay tiempo de probar que las cadenas regulares que planteamos funcionen, y en su oportunidad, escribirlas mediante un método de auténtica "prueba y error".

3.4.3- Uso de Expresiones regualres.

Como mencionamos en la sección de operadores, los operadores principales para usar las expresiones regualres son s/// y m//, pero no ahondamos en los usos que les podemos dar, que no son ni mucho menos, tan patentes como los usos de los operadores convencionales.

Por su utilidad, podemos dividir los principales usos de las expresiones regulares en tres categorías:
BúsquedaDonde el objetivo es verificar la existencia de un patrón en una cadena (ver si la cadena pertenece al lenguaje especificado).
SubstituciónReemplazar una cadena (o lenguaje) por otro, muy útil para modificar sistemáticamente una cadena en una serie de archivos (usando Perl en línea).
ExtracciónTambién se pueden utilizar para extraer subcadenas que cumplan con ciertas características dentro de las cadenas que proporcionemos, que pertenezcan al lenguaje.

3.4.3.1- Búsqueda

Esta es por mucho la mas sencilla de las aplicaciones, simplemente verifica que una cadena cumpla con el lenguaje especificado y regresa un valor lógico para indicar el éxito o el fracaso de la cadena. El uso típico de esta función, es el elaborar una espacie de grep en Perl.

Pasando directamente a los ejemplos:

Si deseamos imprimir solamente las líneas de comentario de un programa en Perl, podríamos escribir el siguiente script.

#/usr/bin/perl
open(AE,"ARGV[0]");	#Abrimos para lectura el archivo dado como primer parámetro.
while($reng=<AE>)
{
  if($reng=~m/^\#/)	#Estrictamente las líneas que inicien con #
  {
    print $reng;
  }
}
close(AE);
Como se puede ver, este script imprimirá todas las líneas del archivo original que inicien con "#", esto ignora los comentarios al final de las líneas, pero este detalle se correge con eliminar el "^" del inicio de la expresión regular.

Si deseamos hacer un demigrep, o supergrep (como se desee) que responda a la siguiente invocación:
grep.pl archivo patrón, siendo el patrón una cadena regular, imprimiendo del archivo dado como parámetro las líneas que cumplan con el.

#/usr/bin/Perl
open(AE,"ARGV[0]");	#Abrimos para lectura el archivo dado como primer parámetro.
while($reng=<AE>)
{
  if($reng=~m/$ARGV[1]/)	#En efecto, al igual que en las "" se substituyen las vairables entre //
  {
    print $reng;
  }
}
close(AE);
La característica de formación dinámica de las cadenas regulares funciona tanto para Perl4 como para Perl5. y puede ser de gran utilidad cuando el patrón que los renglones deben cumplir depende de la información contenida en el mismo archivo. Esta característica la revisamos a fondo en la sección 3.4.4.1

3.4.3.2- Substitución


El uso mas común de las expresiones regualres es el cambiar una cadena por otra cuando así se requiere (dondequiera que este en la cadena original). con lo que se resumen grandes segmentos de código sobretodo en el filtrado de largos archivos de texto.

Esta función se basa en el operador s/// , su sintaxis es:
s/EXP1/EXP2/MOD
donde:
EXP1 Es la expresión que buscamos y que de encontrarla será substituida
EXP2 Es la expresión por la que hemos de substituir la expresión buscada
MOD Es un modificador de la operación del s/// usualmente "g"

Así como el modificador se agrega al final de s/// , se puede agregar al final de la expresión m// , para revisar los modificadores recomiendo que se consulte la referencia en el capitulo de operadores PERLOP y de cadenas regualres PERLRE.

El primer ejemplo, sea el comando de Perl en línea de comando que cambiaría en todos los programas .pl del directorio la ruta de Perl (tarea común cuando se migra un programa de una maquina a otra).

/usr/leng/Perl -pi.bak -e "s/\/usr\/bin\/perl/\/usr\/leng\/perl/g";

En resumen, lo que hace este comando es que todas las ocurrencias de "/usr/bin/Perl" (los / se anteceden de un \ para evitar que se confundan con el final de la expresión regular), sean reemplazadas por "/usr/leng/Perl" cuantas veces aparezcan en un renglón (esa es la función del modificador "g" que no solo se realice una substitución si hay mas de una ocurrencia en la misma cadena).

3.4.4- Variables


Las expresiones regulares se vuelven extremadamente poderosas al agregarles variables, estas aparecen tanto de entrada como de salida.

Las variables de entrada son reemplazadas (como se reemplazan en las cadenas que están entre comillas "") en las expresiones regulares, esto nos da la posibilidad de emplear cadenas regualres determinadas en tiempo de corrida.
Las variables de salida son variables constantes (no podemos modificar sus valores directamente) en las que se colocan las diversas coincidencias de las cadenas regulares con la cadena de prueba, estas nos dan la posibilidad de extraer información de nuestras cadenas de prueba en base a cadenas regulares.

3.4.4.1- Variables de entrada


Hasta ahora, las expresiones regualres a evaluar son constantes, esto es, entre ejecuciones del programa siempre buscamos el mismo lenguaje de la cadena de prueba. Esto es solo un caso particular para Perl, pues determina las expresiones regualres a evaluar en tiempo de corrida, lo que nos da la posibilidad de elaborar expresiones regulares que respondan a las necesidades de cada corrida.
Para esto, Perl substituye el valor de las variables que especifiquemos entre // de modo similar a como lo hace en las cadenas entre paréntesis.

Por ejemplo:

$cadena="1321323palabra"; #Damos valor a la cadena de prueba
$cadena=~s/\w+//g"; #Le aplicamos la expresion regular \w+

Es funcionalmente equivalente a:
$cadena="1321323palabra"; #Damos valor a la cadena de prueba
$expresion="\w+";
#Una cadena que formará parte de la expresion regular $cadena=~s/$expresion//g";#aplicamos la expresion regular a la cadena de prueba

Esto, porque en el segundo código, la expresión regular identifica a $expresion como una variable y substituye su valor en la expresión regular, en este caso \w* , de modo que ambos códigos reemplazaran las "palabras" (o grupos de caracteres alfabéticos contiguos) por la cadena vacía, quitando las "palabras" de la cadena de prueba $cadena.

A primera vista puede no ser muy evidente el uso de esta funcionalidad, pero nos permite diseñar los lenguajes que buscaremos en las cadenas sobre datos obtenidos en tiempo de corrida y actuar acorde a ellos.

Para ejemplificar esta funcionalidad, escribamos un segundo programa para cambiar la ruta al programa de Perl en los propios programas de Perl (aunque no en el presente por supuesto, de modo que habría que ejecutarlo pasando el programa como parámetro a Perl).
Pare esto requeriremos dos parámetros, la vieja ruta y la nueva ruta, y en ellos debemos hacer una consideración especial, si tenemos:

$ruta1="/usr/bin/Perl";
$ruta2="/usr/leng/Perl";
$renglon=~s/$ruta1/$ruta2/g;

Al substituir las rutas en la expresión de substitución obtendríamos un código equivalente al siguiente:

$renglon=~s//usr/bin/perl//usr/leng/perl/g;

Que es erróneo!!!!
Como se puede apreciar, no colocamos los \ antes de los / de modo que los / de las rutas serían interpretados como delimitadores de la cadena regular.

Para corregir este problema existen dos posibles soluciones, uno, emplear algún otro caracter en lugrar de / para delimitar las expresiones regulares, pero por claridad y potencial fallo en caso de que algún posible valor de las variables empleara este nuevo caracter prefiero no emplearlo, para ver como opera recomiendo consultar la referencia en la sección del operador s///.

La segunda posibilidad, que es la que empleamos en el primer script de este propósito que hicimos (en la sección 3.4.3.1) es el colocar \ antes de cada / en la expresión regular de modo que no haya confusión en los limites de nuestra expresión.
Esto podríamos hacerlo con expresiones regulares constantes, pero siendo una tarea muy común, Perl ha implementado una función que realiza el trabajo por nosotros, esta función es quotemeta, cuya sintaxis es:

quotemeta EXPRESIÓN
donde:
EXPRESIÓN es la expresión en la que antecederemos \ a cada caracter que pueda tener alguna interpretación especial en algún tipo de cadena.

Debe notarse que si la empleáramos en una expresión como "\w*" el resultado seria "\\w\*" de modo que seria completamente inocuo como expresión regular (solo implicaría la secuencia literal de los tres caracteres "\","w" y "*".
Sin embargo, para el ejemplo que nos ocupa es justo lo que necesitamos.

Además, para hacer mas breve el programa, hagámoslo operar solo sobre un archivo cuyo nombre (y ruta completa en caso de requerirlo) le pasamos como tercer parámetro.

Aclarado esto, pasemos al código.

#!/usr/bin/Perl
#Esta es una ruta tentativa, supongamos que es correcta o que eludimos usarla.
#recibimos en $ARGV[0] la ruta original
# y en $ARGV[1] la nueva ruta.

$ruta1=quotemeta($ARGV[0]);
$ruta2=$ARGV[1];

system("mv $ARGV[2] $ARGV[2].old");
open(PROG_OR,"<$ARGV[2].old");
open(PROG_N,">$ARGV[2]");
while($renglon=<PROG_OR>)
{
  $renglon=~s/$ruta1/$ruta2/; #solo una substitución por renglón.
  print PROG_N $renglon;
}
close PROG_OR;
close PROG_N;
Expliquemos ahora, por líneas el funcionamiento de este programa:

#!/usr/bin/Perl
#Esta es una ruta tentativa, supongamos que es correcta o que eludimos usarla.
#recivimos en $ARGV[0] la ruta original
#y en $ARGV[1] la nueva ruta.

Para fines prácticos, podemos considerar esto como un mero comentario inicial, pues no estamos seguros de que la posición de Perl sea esta, por lo que habrá de ejecutar este programa como Perl nombre del programa parametro1 parametro2 parametro3 ,nótese que requiere de Perl5.

$ruta1=quotemeta($ARGV[0]);

Esta instrucción copia el valor del primer argumento a la variable $ruta1, teniendo la precaución de colocar \ antes de todo caracter especial para que pueda ser empleado como expresión regular.

$ruta2=$ARGV[1];

El segundo parámetro lo copiamos tal cual, habrá que tener precaución al usarlo para que las / que contengan no interfieran, pero no podrá ser empleado como expresión regular.

system("mv $ARGV[2] $ARGV[2].old");

Movemos el archivo a editar a uno nuevo con el mismo nombre y la extensión ".old" a semejanza del script de la sección 3.4.3.1.

open(PROG_OR,"<$ARGV[2].old");

Abrimos como archivo de entrada el archivo original bajo su nuevo nombre.

open(PROG_N,">$ARGV[2]");

Y abrimos como archivo de salida un archivo recién creado con el nombre original del archivo a editar.

while($renglon=<PROG_OR>){

Iniciamos un ciclo típico para revisar todas las líneas del programa.

$renglon=~s/$ruta1/$ruta2/; #solo una substitución por renglón.

Realizamos la substitución, debe recordarse que solo la primera parte del operador s/// es una expresión regular, y la segunda es solo una cadena que se coloca en lugar de aquellas cadenas que correspondan con la expresión regular.

De modo que $ruta1 efectivamente es empleada como la expresión regular que determina que cadena reemplazar, y $ruta2 solo especifica la cadena a poner en su lugar (no es una expresión regular), como Perl sabe que $ruta2 es solo una cadena no es necesario un manejo especial de esta, Esto no sería cierto si escribiesemos el valor de la expresi&oacutre;n, pues no habría modo de saber cuales / son delimitadores.
Debe quedar bien claro que el operador s/// solo emplea una expresión regular que es $ruta1, y que $ruta2 es una simple cadena que el operador emplea en la substitución.

print PROG_N $renglon;}

Ultima instrucción del ciclo por línea, que imprime la línea ya trabajada por el operador s/// en el archivo de salida.

close PROG_OR;
close PROG_N;

Cerramos los archivos tanto de entrada como de salida al final del programa.

Como se ve, este es un programa muy sencillo, la mayor dificultad que tiene radica en comprender el uso que el operador da a sus operandos, y recomiendo que para una mayor claridad se consulte la referencia en la sección PERLOP en lo referente al operador s///.

Los usos que se le puedan dar a esta característica de las cadenas regualres quedan a la imaginación del programador, pero confío que en cuanto adquiera cierto dominio del lenguaje y se enfrente a problemas mas complejos hallara muchos y muy interesantes usos para esta característica y la siguiente.

3.4.4.2- Variables de salida

Como he mencionado desde la sección 3.4.3 una de las características mas interesantes de las expresiones regulares es su capacidad de extraer información de las cadenas según su forma expresada en expresiones regualres.

El uso de las variables de salida es muy sencillo, cuando planteamos una expresión regular en la que existan paréntesis, las secciones de la cadena de prueba que correspondan con las sub-expresiones regulares contenidas en los paréntesis irán siendo colocadas en las variables $1, $2, $3, etc.

Así por ejemplo, para sacar la parte entera y fraccionaria de un numero como 4532431.243 probaríamos:

$numero="8942389.523";
$numero=~/(\d*)\.(\d*)/
$entero=$1;
$fraccion=$2;

expliquemos este ejemplo línea por línea:

$numero="8942389.523";

Creamos el numero a revisar, recordemos que las expresiones regualres trabajan sobre cadenas, así que a pesar de representar un valor numérico, ahorramos el paso de la conversión y la especificamos directamente como cadena.

$numero=~/(\d*)\.(\d*)/

Realizamos una búsqueda del expresión regular, la expresión regular traducida al castellano es:

busca una cadena de cero o mas dígitos y agrúpalos, luego, busca un punto y luego busca un segundo grupo de cero o mas dígitos y agrúpalos.
Nótese que los dos grupos quedan indicados por las partes de la expresión regular que esta entre paréntesis.

$entero=$1;

Aquí tomamos el valor de la variable constante $1, que contiene la parte de la cadena de prueba que se verifico con el primer grupo de la expresión regular.
en este caso el valor en cuestión es "8942389"

$fraccion=$2;

Y después tomamos el valor del segundo grupo de la expresión regular y lo colocamos en la variable fracción, en este caso "523"

Debe notarse que en este ejemplo el "." no se incluyo en ninguno de los grupos, por lo que no figura en ninguna variable $1,$2, etc.

En este ejemplo el numero de grupos esta claramente definido desde el principio. Lo que no siempre es el caso, por ejemplo, supongamos que deseamos extraer los diversos elementos de un nombre e irlos imprimiendo uno por uno.

$nombre="David Jonathan Sol Llaven";
while($nombre =~ /(\w+)\s*/g)
{
  print $1;
}
Debe notarse de este ejemplo que al emplear el modificador /g del operador m// se van obteniendo las coincidencias una por una, en este caso, y el operador va recordando la posición en que ocurrió la ultima ocurrencia para proseguir con la búsqueda en una ocasión posterior, de no incluir el modificador /g cada nueva vuelta del ciclo while regresaría el mismo elemento, el primero.

Una segunda opción, consisten en obtener el resultado de la expresión en su conjunto, este puede usarse en contexto escalar o en contexto de arreglo, este refinamiento es muy útil si deseamos, por ejemplo, obtener los elementos sacados de la cadena de prueba en grupos, sin embargo, la aplicación resulta un poco mas difícil de comprender y para no confundir los progresos logrados prefiero dejarlo a la investigación del lector.

Así pues, para comprender el funcionamiento de la obtención de los valores de una verificación de expresiones regulares recomiendo revisar la sección de operadores de la referencia, PERLOP, en lo concerniente al operador m// aunado con una saludable dosis de experimentación.

No olvide el lector que como casi cualquier otra característica de Perl, las expresiones regualres están ahí para facilitar las tareas a realizar, por lo que deben de emplearse para resumir largos procesos de búsqueda y separación de cadenas o para atacar problemas de revisión de cadenas.


En esta sección , dada su hostilidad, agradeceré los comentarios y ejemplos que ayuden a la comprensión de esta característica de Perl.