S05-regex-es

TITULO

Synopsis 5: Regexes y Reglas

AUTORES

Damian Conway <damian@conway.org> Allison Randal <al@shadowed.net> Patrick Michaud <pmichaud@pobox.com> Larry Wall <larry@wall.org>

TRADUCCIÓN AL CASTELLANO

Ramiro Encinas Alarza <ramiro.encinas@gmail.com>

VERSIÓN

Creado: 24 Jun 2002

Ultima Modificación: 06 Nov 2009 Versión: 108

Este documento trata sobre la nueva sintaxis de las nuevas regex. Intentaremos llamarlas regex en vez de "expresiones regulares" porque durante mucho tiempo no han sido expresiones regulares, y pensamos que "regex" es un término lo suficientemente conocido como para convertirse técnicamente en "un patrón que haga matching con, como una expresión regular". Por otro lado, uno de los propósitos del nuevo diseño es hacer que las partes de los patrones estén más accesibles al análisis mediante las expresiones regulares tradicionales y mediante el parseo de la semántica, lo que implicaría diferenciar con cuidado en el patrón la parte declarativa de la parte procedimental.

En cualquier caso, cuando se hace referencia gramatical a patrones recursivos, son preferibles los términos rule y token que regex.

Nuevos resultados del match y variables de captura

Uno de los nuevos objetos es la variable $/ que tiene un contexto léxico implícito. Aunque parezca mentira, el acceso al último match por parte del usuario se realiza mediante esta variable. Las variables de captura individuales, como $0, $1, etc., son elementos de $/.

Dicho sea de paso, a diferencia de Perl 5, la numeración de las variables de captura ahora comienzan con $0 en vez de $1. Más detalles después.

Características sintácticas sin cambios

Las siguientes características regex utilizan la misma sintaxis que Perl 5:

    • Captura: (...)
    • Cuantificadores de repetición: *, +, y ?
    • Alternativas: |
    • Escape con la barra invertida (Backslash): \
    • Sufijo de ajuste mínimo del match: ??, *?, +?

Mientras que la sintaxis de | no cambia, sí cambia un poco la semántica por defecto. Estamos intentando preparar una mezcla agradable de matchings declarativos y procedimentales para obtener lo mejor de ambos. No necesitas escribir tu propio lexema porque Perl te escribe uno ya. Más detalles en la sección "Matching con tokens largos".

Simplificación de la interpretación léxica de patrones

A diferencia de las expresiones regulares tradicionales, Perl 6 no necesita que recuerdes una lista arbitraria de metacaracteres. Perl 6 clasifica los caracteres con una regla simple: todos los grafemas base (glyphs) de los caracteres van entre los símbolos mayor/menor/que (_) o tienen una clasificación Unicode comenzando con 'L' (letras) o 'N' (números) y en los regex siempre son literales (auto-match). Además, para que sean metasintácticos tienen que escaparse con un \ (en este caso, un caracter alfanumérico es metasintáctico en sí mismo, pero cualquier otro caracter alfanumérico que inmediatamente le siga, no).

Cualquier otro grafema (espacios en blanco incluidos) son exactamente lo contrario: siempre serán considerados metasintácticos (no auto-match) y deben ser escapados o acotados (con comillas) para convertirlos en literales. Tradicionalmente, pueden escaparse individualmente con \, pero en Perl 6 también pueden ser acotados como sigue.

Las secuencias de uno o más grafemas de cualquier tipo deben convertirse en literales mediante comillas simples. (También se permiten las comillas dobles con las mismas semánticas de interpolación en base al lenguaje donde esté incrustado léxicamente el regex). La acotación (comillas) crea una unidad cuantificable, por tanto

manzana*

cuantifica sólo la 'a' y haría match con "manzanaaa", y

'manzana'*

cuantifica el string completo y haría match con "manzanamanzana".

En esta tabla se resumen las diferencias:

Alfanuméricos No alfanuméricos Mezcla

Grafemas literales a 1 _ \* \$ \. \\ \' K\-9\! Metasintácticos \a \1 \_ * $ . \ ' \K-\9! Grafemas entre comillas 'a' '1' '_' '*' '$' '.' '\\' '\'' 'K-9!'

En otras palabras, los grafemas con identificador son literales (o metasintácticos cuando se escapan), los grafemas sin identificador son metasintácticos (o literales cuando se escapan) y todo es literal entre comillas simples.

Sin embargo, no todos los grafemas sin identificador son metasintácticos en los regexes de Perl 6 (por ej. \1 \_ - !). Es más exacto decir que todos los grafemas sin identificador y sin escapar son potencialmente metasintácticos, y además están reservados para uso futuro. Si los utilizas como una secuencia, tendrás un error en tiempo de compilación donde te aclara que necesitas acotar la secuencia o definir un operador nuevo para que sea reconocido.

El caracter punto y coma (;) se reserva de forma específica como un meta-caracter sin significado; si aparece un punto y coma sin acotar, el compilador dirá que al regex le falta su terminador.

Modificadores

    • Ya no se requiere más la sintaxis extendida(/x)... porque va por defecto. (De por sí, la única forma de volver a la sintaxis antigua es con el modificador antiguo :Perl5/:P5).
    • No existen los modificadores /s o /m (se sustituyen por metacaracteres - ver después).
    • En las sustituciones no existe el modificador de evaluación /e; en vez utiliza:
      • s/patrón/{ hazlo() }/
      • o:
      • s[patrón] = hazlo()
      • En vez de /ee escribe:
      • s/patrón/{ eval hazlo() }/
      • o:
      • s[patrón] = eval hazlo()
    • Los modificadores ahora se colocan al comienzo de un match/sustitución:
      • m:g:i/\s* (\w*) \s* ,?/;
      • Cada modificador debe comenzar con sus dos puntos (:). El delimitador debe estar separado del último modificador con un espacio en blanco si es un argumento del modificador precedente (sólo si el caracter siguiente es un paréntesis abierto).
    • Los modificadores de un caracter también tienen versiones largas:
      • :i :ignorecase :a :ignoreaccent :g :global
    • El modificador :i (o :ignorecase) ignora mayúsculas/minúsculas en el contexto léxico, no en su contexto dinámico. Esto es, las subreglas siempre utilizan sus propias configuraciones de mayúsculas/minúsculas.
      • La variante :ii (o :samecase) puede utilizarse en una sustitución para aplicar el patrón de mayúsculas/minúsculas del string que ha realizado el match al string sustituido.
      • Si se produce el match del patrón sin el modificador :sigspace, la información de mayúsculas/minúsculas se conserva caracter por caracter. Si el string de la derecha es más largo que el de la izquierda, se aplica las mayúsculas/minúsculas del caracter final. Si es posible, la capitalización de una letra se conserva independientemente de si la letra resultante está al principio de la palabra o no; si ahí no hay un caracter capitalizado, se utilizará el caracter correspondiente en mayúsculas. (Esta política puede modificarse en el contexto léxico, dependiendo de las reglas de ortografía del lenguaje que afecten a su Unicode y a la capitalización). Los caracteres que no incorporen información acerca de mayúsculas/minúsculas dejan su caracter correspondiente de sustitución sin cambios.
      • Si el patrón hace match con :sigspace, se utiliza un algoritmo inteligente que intentará determinar si existe una política de capitalización uniforme sobre cada match de cada palabra, y aplicará esa misma política a cada palabra reemplazada. Si en la izquierda no se encuentra una política uniforme, la política para cada palabra se mantiene palabra por palabra, replicando la última palabra del patrón si es necesario. Si una palabra no tiene una política reconocida, la palabra en cuestión se procesa caracter por caracter como si no se aplicara :sigcase. Las políticas reconocidas son:
      • lc() uc() ucfirst(lc()) lcfirst(uc()) capitalize()
      • En cualquier caso, sólo se tiene en cuenta la parte del string que hace match con el patrón correspondiente. Queda fuera del análisis cualquier tipo de match lookahead o contextual.
    • El modificador :a (:ignoreaccent) funciona igual que :ignorecase, ignorando los acentos en vez de mayúsculas/minúsculas. Es lo mismo que tomar cada grafema (tanto del patrón como del destino), convertirlos a NFD (descomposición máxima) y comparar los dos caracteres base (caracteres no marcados como Unicode) ignorando cualquier marca que pudieran llevar. Sólo se ignoran las marcas de los caracteres para determinar si la aserción es cierta; el texto del match en cuestión incluye todos los caracteres ignorados, incluyendo cualquiera que se encuentre después del último caracter base.
      • La variante :aa (:sameaccent) puede utilizarse en una sustitución para cambiar el string sustituido con el mismo patrón de acento del match del string. Se tiene en cuenta la información del acento de cada caracter. Si el string de la derecha es más largo que el de la izquierda, el resto de caracteres se sustituyen sin modificarlos. (Las diferencias entre NDF/NFC normalmente son inmateriales porque Perl las encapsula en modo grafema). Con el modificador :sigspace, las reglas anteriores se aplican palabra por palabra.
    • El modificador :c (:continue) hace que el escaneo del patrón comience desde la posición especificada (por defecto en $/.to):
      • m:c($p)/ patrón / # comienza a escanear en la posición $p
      • Esto no quiere decir que el patrón se ancle automáticamente en la ubicación de comienzo (para ello utiliza :p). El patrón que se le da a split lleva implícito el modificador :c.
      • Las posiciones string son de tipo StrPos y generalmente deben tratarse como opacas.
    • El modificador :p (:pos) intenta que el patrón sólo haga match en la posición string especificada:
      • m:pos($p)/ patrón / # match en la posición $p
      • Si no se pone el argumento, por defecto es $/.to. (A diferencia de Perl 5, el string en sí no da pista sobre donde terminó el último match). Todos los matches de las subreglas pasan su posición de comienzo de forma implícita. Igualmente, el patrón que le das a un rasgo is parsed de una macro de Perl lleva implícito el modificador :p.
      • Fíjate que
      • m:c($p)/patrón/
      • es de forma ruda, equivalente a
      • m:p($p)/.*? <( patrón )> /
    • El nuevo modificador :s (:sigspace) tiene en cuenta las secuencias de espacios en blanco. Sin este modificador también se pueden indicar estas secuencias de espacios en blanco en el patrón con <.ws>. Esto es,
      • m:s/ next cmd '=' <condición>/
      • es lo mismo que:
      • m/ <.ws> next <.ws> cmd <.ws> '=' <.ws> <condición>/
      • lo cual es efectivamente lo mismo que:
      • m/ \s* next \s+ cmd \s* '=' \s* <condition>/
      • Pero en el caso de
      • m:s{(a|\*) (b|\+)}
      • o igualmente,
      • m { (a|\*) <.ws> (b|\+) }
      • <.ws> no puede decidir qué hacer hasta que no vea los datos y sigue haciendo su trabajo. Si no, define tu propio ws y :sigspace para evitarlo.
      • Normalmente no necesitarás :sigspace dentro de las gramáticas porque las reglas de interpretación manejan automáticamente los espacios en blanco por tí. En este contexto, los espacios en blanco a menudo incluyen comentarios, dependiendo de cómo la gramática elija definir su regla de espacios en blanco. Aunque la subregla <.ws> por defecto reconoce construcciones sin comentarios, cualquier gramática es libre de omitir la regla. La regla <.ws> no tiene la intención de querer decir siempre lo mismo.
      • También es posible pasar un argumento a :sigspace especificando la aplicación de una subregla completamente distinta. Puede ser cualquier regla sin hacer match con espacios en blanco. Cuando hablamos de este modificador es importante distinguir el significado de espacio en blanco en el patrón del "espacio en blanco" que hará match, por tanto, llamamos al espacio en blanco del patrón sigspace y normalmente reservamos espacio en blanco para indicar cual <.ws> hace match en la gramática en cuestión. La correspondencia entre sigspace y espacio en blanco es fundamentalmente una metáfora, por eso es tan útil y tan (potencialmente) confusa.
      • La variante :ss (:samespace) puede utilizarse en sustituciones para hacer mapeos inteligentes de espacios. Por cada llamada realizada con sigspace a <ws> en la izquierda, el espacio en blanco que hace match se copia sobre la posición correspondiente en la derecha y se representa como un sólo espacio en blanco en el string reemplazado. Si hay más posiciones de espacios en blanco en la derecha que en la izquierda, permanecerán los de la derecha. Si no hay suficientes posiciones de espacios en blanco en la derecha para mapear todas las posiciones de espacios en blanco disponibles, el algoritmo intenta minimizar la pérdida de información uniendo los espacios en blanco "comunes" fuera de la lista de espacios en blanco. De menor costo al mayor, el orden es:
      • espacios tabulaciones el resto de espacios en blanco horizontales, Unicode incluido líneas nuevas (incluyendo a crlf como una unidad) el resto de espacios en blanco verticales, Unicode incluido
      • La intención fundamental de estas reglas es que cuando se produzcan en una sustitución, poder minimizar en cada línea los problemas con el formato y similares. Por supuesto que no hay garantía de que el resultado sea exactamente igual de cómo lo haría un humano.
      • El modificador :s se utiliza para definir y hacer variaciones de los matchs:
      • mm/match de algunas palabras/ # igual que m:sigspace ss/match de algunas palabras/sustituye esas palabras/ # igual que s:samespace
      • ss/// actúa como si fuera un :ss, esto es:
      • $_ = "a b\nc\td"; ss/b c d/x y z/;
      • tiene como resultado un valor de "a x\ny\tz".
    • Hay nuevos modificadores que especifican el nivel de Unicode:
      • m:bytes / .**2 / # match de dos bytes m:codes / .**2 / # match de dos codepoints m:graphs / .**2 / # match de dos grafemas independientes del lenguaje m:chars / .**2 / # match de dos caracteres en el nivel máximo actual
      • Hay pragmas por defecto que se corresponden con estos niveles. El modificador :chars siempre se redunda porque los puntos siempre hacen match sobre los caracteres en el nivel más alto permitido por el contexto. Este nivel (el más alto), debe ser el mismo que el nivel más alto de los otros tres niveles, o debe ser más específico que :graphs cuando se utilizan reglas del lenguaje en particular que afecten a los caracteres. No puedes especificar un procesamiento de caracteres que dependa del lenguaje sin especificar ese lenguaje. [Conjetura: el modificador :chars puede tomar un argumento que especifique qué reglas de lenguaje utilizará para el match].
    • El nuevo modificador :Perl5/:P5 permite el uso de la sintaxis de las regex de Perl 5 (pero no llega a permitir que puedas poner tus modificadores al final). Por ejemplo,
      • m:P5/(?mi)^(?:[a-z]|\d){1,2}(?=\s)/
      • es equivalente a esta sintáxis de Perl 6:
      • m/ :i ^^ [ <[a..z]> || \d ] ** 1..2 <?before \s> /
    • Un entero como modificador especifica el número de veces (contador) que se realizará el match. El tipo de contador se determina por el caracter que lo sigue.
    • Si le sigue una x, significa repetición. La forma general es :x(4). Esto es
      • s:4x [ (<.ident>) '=' (\N+) $$] = "$0 => $1";
      • es lo mismo que:
      • s:x(4) [ (<.ident>) '=' (\N+) $$] = "$0 => $1";
      • y casi es lo mismo que:
      • s:c[ (<.ident>) '=' (\N+) $$] = "$0 => $1" for 1..4;
      • con la excepción de que el string no cambia a menos que se produzcan los cuatro matches. Puedes especificar el rango que quieras entre uno y cuatro en la forma :x(1..4).
    • Si al número le sigue un st, nd, rd, o th, significa encontrar la ocurrencia N. La forma general es :nth(3). Esto es
      • s:3rd/(\d+)/@datos[$0]/;
      • es lo mismo que
      • s:nth(3)/(\d+)/@datos[$0]/;
      • y también es lo mismo que:
      • m/(\d+)/ && m:c/(\d+)/ && s:c/(\d+)/@datos[$0]/;
      • Se permiten las listas y las uniones: :nth(1|2|3|5|8|13|21|34|55|89).
      • Y también las llaves: :nth({.is_fibonacci})
    • Con el nuevo modificador :ov (:overlap), el regex actual hará match en todas las posiciones de caracter posibles (aunque se den solapadas) y devuelve todos los matches en una lista o como items independientes. Se devuelve el primer match en cualquier posición. Se garantiza que los matches se devuelvan en orden de izquierda a derecha respecto a las posiciones de comienzo.
      • $str = "abracadabra";
      • if $str ~~ m:overlap/ a (.*) a / { @substrings = @@(); # bracadabr cadabr dabr br }
    • Con el nuevo modificador :ex (:exhaustive), el regex en cuestión hará match en todas las formas posibles (aunque se den de forma solapada) y devuelve todos los matches en una lista, o como items independientes. Se garantiza la devolución de los matches en orden de izquierda a derecha respecto a las posiciones de comienzo. No se garantiza el orden de cada posición de comienzo y dependerá de la naturaleza del patrón y del motor de matching. (Conjetura: o podríamos forzar la semántica del motor de backtracking, o podríamos no garantizar el orden a menos que el patrón comience con "::" o algo como eliminar las soluciones basadas en DFA).
      • $str = "abracadabra";
      • if $str ~~ m:exhaustive/ a (.*?) a / { say "@()"; # br brac bracad bracadabr c cad cadabr d dabr br }
      • El ~~ devuelve el resultado del primer match cuando éste se produce, mientras que el resto de los matches los puede devolver @().
    • El nuevo modificador :rw hace que el regex prefiera la modificación del string en vez de asumir semánticas de copia-en-escritura (copy-on-write). Todas las capturas en $/ se convierten en lvalues dentro del string. Por ejemplo, si modificas $1, el string original se modifica en esa ubicación y las posiciones del resto de campos se modifican de acuerdo a ello. Si no se utiliza este modificador (especialmente sino está implementado todavía, o si nunca se implementa), todas las partes de $/ se tratan en base a copia-en-escritura (menos las de sólo lectura).
      • [Conjetura: esto realmente asocia un patrón a una variable string, no a un valor string (que se supone que no cambia)].
    • El nuevo modificador :keepall hace que el regex y todas sus subreglas invocadas recuerden todo, incluso si las reglas por sí mismas no hacen que sus subreglas recuerden sus resultados. Esto sirve para forzar a la gramática a no prescindir de los espacios en blanco y los comentarios.
    • El nuevo modificador :ratchet hace que el regex no realice backtrack por defecto. (Normalmente no utilizarás directamente este modificador, porque va implícito en las declaraciones token y rule). El efecto de este modificador es implicar a los : (dos puntos) después de cada construcción que haga backtrack, incluyendo los cuantificadores *, + y ?, así como los alternadores. (Nota: se ignoran los : para las partes y patrones con análisis largos de tokens porque el backtracking no es necesario en estos casos).
    • Los modificadores :i, :s, :Perl5 y los que soporten Unicode pueden ser ubicados dentro del regex (y tienen contexto léxico):
      • m/:s justificación '=' [:i izquierda|derecha|cent[ro|rado]] /
      • Los argumentos de los modificadores externos sólo podrán ir entre paréntesis. En concreto:
      • m/:foo[xxx]/ Se interpreta como :foo [xxx] m/:foo{xxx}/ Se interpreta como :foo {xxx} m/:foo<xxx>/ Se interpreta como :foo <xxx>
    • El usuario puede definir modificadores:
      • m:lioso/patrón/;
    • Los modificadores definidos por el usuario también pueden llevar argumentos, pero sólo entre paréntesis:
      • m:lioso('crudo')/patrón/;
    • Si quieres utilizar paréntesis en el patrón, tienes que separarlo:
      • m:lioso (patrón);
      • o puedes finalizar con el patrón:
      • m:lioso(argumentos); patrón ;
    • Cualquier gramática regex realmente es un tipo de método y debes declarar las variables utilizando un punto y coma ; seguido de cualquier declaración interpretada por la gramática de Perl 6, incluyendo my, our, state y constant. Una sola declaración (que termine en punto y coma) normalmente se parsea como código Perl 6:
      • token prueba-parseo-nodeterminante { :my $umbral = rand; 'puedeser' \s+ <it($umbral)> }
      • Los matches con tokens largos continúan a pesar de estas declaraciones, por tanto, puede utilizarse una declaración (de otro modo inútil) para tener en cuenta efectos secundarios sin cambiar el funcionamiento de los matches del patrón que sigan después:
      • rule rompedor { :state $ = say "he llegado aquí al menos una vez"; ... }

Cambios en los metacaracteres

    • Un punto . ahora hace match con cualquier caracter (fin de línea incluido). (Ya no existe el modificador /s.)
    • ^ y $ ahora siempre hacen match en el comienzo/final del string, como los viejos \A y \z. (El modificador /m ya no existe). En la parte derecha de un operador ~~ o !~~ incrustado, siempre harán match al comienzo/final del submatch indicado porque a ese submatch se le trata, lógicamente, como un string independiente.
    • $ ya no hace match después de \n, por tanto, si quieres que lo haga es necesario decir \n?$.
    • \n ahora hace match como la nueva línea lógica (da igual la plataforma), no como \x0a.
    • Ya no existen los metacaracteres \A, \Z, y \z.

Metacaracteres nuevos

    • Por defecto es /x:
        • Ahora un # es el comienzo de un comentario. Si le sigue una comilla invertida y un paréntesis, llave o corchete abierto, comienza un comentario incrustado que finaliza con el paréntesis, llave o corchete cerrado. Si no, el comentario finaliza con nueva línea.
        • El espacio en blanco ahora siempre es metasintáctico, no hace match de forma literal y sólo se utiliza para diseño (ver el modificador :sigspace descrito antes).
    • ^^ y $$ hacen match al principio y al final de la línea. (El modificador /m ya no existe). Ambos son aserciones de ancho-cero. $$ hace match antes de cualquier \n (nueva línea lógica), y también al final del string si el último caracter no es un \n. ^^ siempre hace match al principio del string y después de cualquier \n que no sea el último caracter del string.
    • . hace match en un loquesea, mientras que \N hace match en un loquesea menos la nueva línea. (El modificador /s ya no existe). En concreto, \N no hace match en el retorno de carro ni en el salto de línea.
    • El nuevo metacaracter & separa términos unidos. Los patrones en cada lado deben hacer match con el mismo punto de comienzo y fin. Nota: si no quieres que tus dos términos terminen en el mismo punto, entonces tendrás que utilizar lookahead.
      • Al igual que los separadores | y ||, las uniones tienen ambas formas & y &&. La forma & se considera declarativa en vez de procedimental; y ello permite al compilador y/o al sistema en tiempo de ejecución decidir qué partes evaluar primero (es erróneo suponer que en cada lado se produce el orden de forma sistemática). La forma && garantiza el orden de izquierda a derecha y el backtracking hace que el argumento de la derecha sea más rápido que el de la izquierda. En otras palabras, && y || establecen puntos de secuencia. En la parte izquierda puede hacerse un backtrack en caso de permitirse el backtracking en toda la construcción.
      • El operador & es una lista asociativa como |, pero tiene una pequeña y ligera precedencia. Igual que && tiene una pequeña y ligera precedencia sobre ||. Al igual que con los operadores de unión y con los operadores de cortocircuito, & y | tienen más preferencia que && y ||.
    • Los operadores ~~ y !~~ hacen que un submatch se realice allá donde se realizó el match de la variable o unidad en la izquierda. Los anclajes string consideran que el submatch tiene que producirse en todo el string. Por ejemplo, puedes hacer match con cualquier identificador que no contenga la palabra "mosca":
      • <ident> !~~ 'mosca'
      • En contraste con
      • <ident> !~~ ^ 'mosca' $
      • podría permitir cualquier identificador (incluyendo cualquier identificador que contenga "mosca" como un substring) mientras el match en su conjunto no es igual a "mosca". (Ten en cuenta que los anclajes ajustan el submatch al principio y al final del identificador como si ese fuera el match entero). Cuando esto forma parte de un match más largo, para que sea más claro, es bueno utilizar más acotación [corchetes]:
      • [ <ident> !~~ ^ 'mosca' $ ]
      • El orden de precedencia de C <~~> y C <!~~> es el mismo entre las versiones de unión y de secuencia de los operadores lógicos de las expresiones de Perl en condiciones normales (ver S03). De ahí
      • <ident> !~~ 'mosca' | 'hormiga'
      • se interpreta como
      • <ident> !~~ [ 'mosca' | 'hormiga' ]
      • mientras que
      • <ident> !~~ 'mosca' || 'hormiga'
      • se interpreta como
      • [ <ident> !~~ 'mosca' ] || 'hormiga'
    • El C <~> es un operador de ayuda para hacer match de subreglas anidadas teniendo como objetivo un terminador específico. Está diseñado para ser colocado entre acotaciones (paréntesis) de esta forma:
      • '(' ~ ')' <expresión>
      • Sin embargo, la mayoría de las veces ignora el argumento de la izquierda y opera en las dos siguientes unidades (que deben ser cuantificadas). En las dos unidades siguientes se produce un "giro" de forma que hacen match en orden inverso. De ahí que la expresión anterior es la versión corta de:
      • '(' <expresión> ')'
      • Más allá, cuando sobreescribe las unidades también inserta el aparato que configurará la expresión interna que reconoce al terminador, y producirá un mensaje de error si la expresión interna no finaliza con la unidad de cierre requerida. Por tanto, pon más atención al paréntesis de la izquierda, porque en realidad sobreescribe nuestro ejemplo con algo más parecido a esto:
      • $<APERTURA> = '(' <ESTABLECE_OBJETIVO: ')'> <expresión> [ $OBJETIVO || <FALLO_OBJETIVO> ]
      • Puedes utilizar esta construcción para realizar construcciones de cierre incluso cuando no tengan un paréntesis de apertura:
      • <?> ~ ')' \d+
      • Aquí, <?> devuelve true en el primer string null.
      • Por defecto, el mensaje de error utiliza el nombre de la regla en cuestión como un indicador de la interpretación de la abstracción del objetivo en ese punto. Sin embargo, a menudo esto es terrible porque los nombres de las reglas se basan en esquemas internos que no tienen sentido. El adverbio :dba("haciendo algo como") puede utilizarse para dar un nombre más informativo que el código que le siga y que intente parsearlo:
      • token postfix:sym<[ ]> { :dba('array subscript') '[' ~ ']' <expresión> }
      • Entonces, en vez de tener un mensaje como este:
      • Unable to parse expression in postfix:sym<[ ]>; couldn't find final ']'
      • tendrás un mensaje como este otro:
      • Unable to parse expression in array subscript; couldn't find final ']'
      • (El adverbio :dba también puede utilizarse para poner nombres a los alternadores y a las alternativas, para mejorar la interpretación de los mensajes de error).

Racionalización de acotaciones

    • (...) todavía acota a un grupo de captura. Sin embargo, el orden de los grupos es jerárquico en vez de lineal. Consulta Capturas de subpatrones anidados.
    • [...] ya no es una clase de caracter. Ahora acota un grupo que no captura.
    • {...} ya no cuenta repeticiones. Ahora delimita una acotación (con llaves) incrustada. Esto siempre es considerado procedimental en vez de declarativo; establece un punto en la secuencia entre lo que va antes y lo que viene después. (Para evitar esto utiliza <?{...}> como sintaxis de la aserción). Una acotación con llaves dentro de un regex establece su propio alcance léxico.
    • Puedes hacer una llamada a código Perl como parte de un match de un regex utilizando las llaves. El código incrustado normalmente no afecta al match y sólo se utiliza para otros efectos:
      • / (\S+) { print "string no vacío\n"; $texto = $0; } \s+ { print "pero contiene espacios en blanco\n" } /
      • La función make utiliza una reducción explícita que genera el objeto del árbol de sintaxis abstracta (objeto abstracto o ast, para abreviar) para este match:
      • / (\d) { make $0.sqrt } El resto /;
      • En vez del string, esto captura la raíz cuadrada del string convertido a número. La parte El resto hace match y se devuelve como parte del objeto Match pero no es devuelto como parte del objeto abstracto. Como normalmente el objeto abstracto representa el nodo más alto de un árbol de sintaxis abstracta, mediante el método .ast puede extraerse el objeto abstracto del objeto Match.
      • Una segunda llamada a make sustituye a cualquier llamada anterior a make.
      • Estas llaves se invocan con el tópico $_ del estado actual del match (es un objeto Cursor). Dentro de las llaves, la posición instantánea de una búsqueda se obtiene con el método .pos de ese objeto. Como con todas las posiciones del string, no hay que tratarla como un número a menos que tengas mucho cuidado y sepas con qué unidades estás tratando.
      • El objeto Cursor también puede devolver el elemento original contra el que estamos haciendo match mediante el método .orig.
      • Con las llaves también se garantiza el comienzo con el objeto Match $/, el cual representa el match en ese momento. Pero, si en las llaves hay un matching interno propio, su variable $/ tendrá como resultado el rebote de ese match hasta la llave de cierre incrustado. (Después del cierre, el objeto continuará con el resultado actual del match). Tanto $/ como tienen el mismo comienzo en las llaves).
    • Si se llama a fail puede afectar al match:
      • / (\d+) { $0 < 256 or fail } /
      • Como las llaves establecen un punto en la secuencia, se garantiza que se llamará en el momento canónico, incluso si el optimizador prueba que después de ellos no puede hacer match. (Sin embargo, cualquier cosa antes está bien. En concreto, las llaves, a veces sirven como terminador de un patrón de token largo).
    • Normalmente el especificador de repetición ahora es ** para un matching máximo, con el correspondiente **? para un matching mínimo. (Todos los cuantificadores parecidos ahora van directamente después de **). Se permiten espacios en cualquier lado del cuantificador completo. Este espacio se considera significativo bajo el modificador :sigspace y será distribuido como una llamada a <.ws> entre todos los elementos del match, pero no en cada extremo.
      • El siguiente token determina que tipo de repetición se desea:
      • Si lo siguiente es un entero, se interpreta como un conteo exacto o un rango:
      • . ** 42 # hace match exactamente 42 veces <item> ** 3..* # hace match 3 o más veces
      • Esta forma se considera declarativa.
      • Si pones unas llaves, devolvería un objeto Int o Range.
      • 'x' ** {$m} # conteo exacto especificado en las llaves <foo> ** {$m..$n} # rango especificado en las llaves
      • / el valor es (\d **? {1..6}) con ([ <alpha>\w* ]**{$m..$n}) /
      • No es posible especificar una lista, daría error:
      • / [foo] ** {1,3} /
      • La forma acotada siempre se considera procedimental, por tanto, la modificación del item nunca se considera parte del token más largo.
      • Si proporcionas cualquier otra unidad (que debe ser cuantificada), se interpreta como un separador (como un operador entre dos operandos), y el primer elemento se cuenta por el número de veces que aparezca entre los elementos:
      • <alt> ** '|' # repetición controlada por la presencia de un caracter <addend> ** <addop> # repetición controlada por la presencia de una subregla <item> ** [ \!?'==' ] # repetición controlada por la presencia de un operador <file>**\h+ # repetición controlada por la presencia de un espacio en blanco
      • Cuando se produce un match con un cuantificador como los vistos, siempre termina "en el medio", esto es, después del primer elemento y antes del siguiente separador. Por tanto
      • / <ident> ** ',' /
      • puede hacer match con
      • foo foo,bar foo,bar,baz
      • pero nunca con
      • foo, foo,bar,
      • Se permite que el separador sea de ancho-cero y tan largo como el patrón de la izquierda que prosigue con cada iteración:
      • . ** <?mismo> # secuencia de match de caracteres idénticos
      • El separador siempre hace match teniendo en cuenta el siguiente elemento; si el separador hace match pero el siguiente elemento falla, hace un backtrack hasta el separador. Igualmente, el match del separador no cuenta de forma "progresiva" bajo el modificador :ratchet a menos que termine con el siguiente elemento.
      • Cuando se utiliza un espacio significativo con :sigspace y algún separador, se aplica a ambos lados del separador, por tanto
      • mm/<elemento> ** ','/ mm/<elemento>** ','/ mm/<elemento> **','/
      • todos permiten el espacio en blanco alrededor del separador, como esto:
      • / <elemento>[<.ws>','<.ws><elemento>]* /
      • mientras que
      • mm/<elemento>**','/
      • no tiene en cuenta a todos los espacios en blanco significativos:
      • / <elemento>[','<elemento>]* /
      • En cualquier caso y de forma explícita puedes hacer match de espacios en blanco si es necesario, y para hacerlo después de una coma pero no antes, puedes poner:
      • / <elemento>**[','\s*] /
    • <...> ahora son delimitadores metasintácticos extensibles o aserciones (reemplazan a la sintáxis (?...) de Perl 5).

No interpolación de variables

    • En los regexes de Perl 6, las variables no se interpolan.
    • Pasan crudas al motor regex, el cual decide cómo manejarlas (más información después).
    • Por defecto, el motor hace match de un string escalar literalmente '...' (no trata al string interpolado como un subpatrón). Dicho de otra forma, en Perl 6:
      • / $var /
      • es como cuando en Perl 5 escribíamos:
      • / \Q$var\E /
      • No obstante, si $var contiene un objeto Regex, en vez de intentar convertirlo a un string, se le llama como a una subregla, como si dijeras <$var>. (Ver aserciones después). Esta forma no realiza captura, y falla si $var proviene fuera del programa (como la comprobación taint (-T)).
      • Si $var no está definida, aparece una advertencia y el match falla.
      • [Conjetura: cuando permitimos hacer match contra tipos no string, hacer un match de tipos en el nodo actual requerirá la sintaxis de una firma incrustada, no una variable vacía, por eso ahí no es necesaria una variable que contenga un objeto de tipo, donde por definición no está definido y de ahí que falle el match por la regla anterior].
      • Sin embargo, no se utiliza para el match la variable de la izquierda de un alias o de un operador submatch.
      • $x = <ident> $0 ~~ <ident>
      • Si quieres hacer match de $0 de nuevo y utilizarlo como el submatch, puedes forzar el match utilizando comillas dobles:
      • "$0" ~~ <ident>
      • Por otro lado, no afecta a un alias o a algo que no sea una variable:
      • "$0" = <ident> # ERROR $0 = <ident> # ok $x = <ident> # ok, captura temporal $<x> = <ident> # ok, captura persistente <x=ident> # lo mismo
      • Las variables declaradas en la captura del alias actúan léxicamente en el resto de la regex. No debes confundir este uso de = con la asignación ordinaria o la referencia ordinaria. Debes tratar a = más como una pseudoasignación de una declaración que una asignación normal. Es más parecido al operador ordinario :=, porque a nivel de regex los strings no cambian y las capturas realmente son valores substr precomputados. No obstante, la substr puede copiarse cuando utilices eventualmente los valores de forma independiente y entonces originalmente es más como una asignación.
      • Las variables de captura en la forma $<ident> puede persistir más allá del alcance léxico; si hay match, se recuerdan en el hash del objeto Match mediante la clave correspondiente al identificador del nombre de la variable. Todo lo contrario que el límite de la persistencia de las variables numéricas como $0, etc.
      • La captura realizada por = crea una nueva variable léxica sino existe ya en el alcance léxico actual. Para capturar una variable léxica externa tienes que poner un OUTER:: como parte del nombre, o realizar la asignación desde dentro de una acotación.
      • $x = [...] # captura hacia la propia $x léxica $OUTER::x = [...] # captura hacia la $x léxica existente [...] -> $tmp { let $x = $tmp } # captura hacia la $x léxica existente
      • Sin embargo, en las variables compartidas, no se garantiza el uso independiente de let (y temp), por tanto, no las utilices.
    • Un array interpolado:
      • / @cmds /
      • hace match mediante la alternación de sus elementos. Utiliza semánticas de unión:
      • / [ @cmds[0] | @cmds[1] | @cmds[2] | ... ] /
      • Sin embargo, si el array es miembro directo de una lista ||, se utilizan semánticas secuenciales aúnque sea el único miembro de la lista. Puedes poner || antes del primer miembro de la alternación, así
      • / || @cmds /
      • equivale a
      • / [ @cmds[0] || @cmds[1] || @cmds[2] || ... ] /
      • Y también, por supuesto
      • / | @cmds /
      • para dejar claro que utilizas semánticas de unión.
      • Igual que con las variables escalares, cada elemento hace match literalmente a menos que sea un objeto Regex, y en este caso hace match como una subregla. Nunca funcionará una subregla escalar no comprobada (tainted). Mientras que los valores Regex tienen su propia configuración para :ignorecase y :ignoreaccent, los valores strings usan los :ignorecase y :ignoreaccent que estén en ese momento.
      • Cuando te canses de escribir:
      • token sigil { '$' | '@' | '@@' | '%' | '&' | '::' }
      • puedes escribir:
      • token sigil { < $ @ @@ % & :: > }
      • pero tienes que poner especial cuidado de poner un espacio después del primer "menor que" para que no se interprete como una subregla. Con el espacio se parsea igual que entre "menor que y mayor que" en Perl 6 ordinario, y se trata como un valor de array literal.
    • Como alternativa, si predeclaras una proto regex, puedes escribir varias regexes para la misma categoría, diferenciándose sólo mediante el símbolo con el que haga match. El símbolo se especifica como parte del "nombre largo". También puede hacer match dentro de la regla utilizando <sym>, así:
      • proto token sigil { } multi token sigil:sym<$> { <sym> } multi token sigil:sym<@> { <sym> } multi token sigil:sym<@@> { <sym> } multi token sigil:sym<%> { <sym> } multi token sigil:sym<&> { <sym> } multi token sigil:sym<::> { <sym> }
      • (multi es opcional y normalmente se omite).
      • Esto puede verse como una forma que permite varias opciones, menos cuando está basado en un match de token largo en vez de un match de identificación. La ventaja de escribir esto así es que es fácil agregar más reglas a la misma categoría con una gramática derivada. Cuando intentes hacer match con /<sigil>/, todos ellos harán match de forma paralela.
      • Si hay parámetros formales en los métodos regex, todavía primero se realizan los matches con reglas que tengan el token más largo. Si hay dos o más iguales, se realiza utilizando los argumentos del resto de las variantes, asumiendo que puedan diferenciarse por tipo.
    • El uso de variables hash en los patrones está reservado.
    • De momento, los match de variables se consideran declarativos, basándonos en que asumimos que el contenido de la variable no cambie con frecuencia. Si cambia, se puede forzar que se calcule de nuevo confiando en su supuesta naturaleza declarativa. (Si sabes que esto va a ocurrir con demasiada frecuencia, pon algún tipo de punto en la secuencia antes de la variable para desactivar el análisis estático como puede ser la generación automática de tokens largos).

Metasintaxis extensible (<...>)

Tanto < como > son metacaracteres, y normalmente (pero no siempre) se utilizan en parejas de matches. (Algunas combinaciones de metacaracteres funcionan como tokens independientes, y pueden incluir "mayor que" y "menor que". Más abajo se describe). La mayoría de las aserciones se consideran declarativas, mientras que las aserciones procedimentales se marcan como excepciones.

Para las parejas de matches, el primer caracter después de < determina la naturaleza de la aserción:

    • Si el primer caracter es un espacio en blanco, el "mayor que" "menor que" se tratan como un array literal de "palabras entre comillas".
      • < manolo & lucia > # es equivalente a [ 'manolo' | '&' | 'lucia' ]
      • Fíjate que el espacio antes del último > es opcional y por tanto valdría < manolo & lucia>.
    • Si el primer caracter es alfabético quiere decir que es una aserción gramatical de captura (por ej. una subregla o un nombre de clase de caracter - ver más abajo):
      • / <signo>? <mantisa> <exponente>? /
      • El primer caracter después del identificador determina el tratamiento del resto del texto antes del "mayor que" de cierre. La semántica que trabaja en segundo plano es la de una función o una llamada al método. Si el primer caracter es un paréntesis abierto, se trata realmente de una llamada.
      • <foo('bar')>
      • Si el primer caracter después del identificador es un =, el identificador es tomado como un alias de lo que sigue. En concreto,
      • <foo=bar>
      • es la forma corta de
      • $<foo> = <bar> Se permiten múltiples alias, por tanto
      • <foo=pub=bar>
      • Es la abreviación de
      • $<foo> = $<pub> = <bar>
      • Si el primer caracter después del identificador es un espacio en blanco, el texto siguiente (después de cualquier espacio en blanco) se pasa como un regex, por tanto:
      • <foo bar>
      • es más o menos igual a
      • <foo(/bar/)>
      • Para pasar un regex con un espacio en blanco al inicio, debes usar paréntesis.
      • Si el primer caracter son los dos puntos seguido de un espacio en blanco, el resto del texto es tomado como una lista de argumentos para el método, igual que en la sintaxis normal de Perl. Por tanto, lo siguiente significa lo mismo:
      • <foo('foo', $bar, 42)> <foo: 'foo', $bar, 42>
      • No se permite ningún otro caracter después del identificador inicial.
      • Los matches de las subreglas se consideran declarativos dentro del alcance del frontal de la subregla que se considere así misma declarativa. El match de la subregla se realizará en el punto de secuencia (si lo tiene). El match de un token largo no funciona en pasado como en una subregla.
    • Si comienza con ., una aserción con nombre no realiza la captura del match (ver http://perlcabal.org/syn/S05.html#Subrule_captures). Por ejemplo:
      • / <ident> <ws> / # $/<ident> y $/<ws> se capturan / <.ident> <ws> / # sólo se captura $/<ws> / <.ident> <.ws> / # no hay captura
      • En cualquier otro caso, la aserción se interpreta igual que una aserción que comienze con un identificador, siempre que venga un identificador después del punto. Al igual que con los identificadores, los que sean adicionales y que estén relacionados con el motor del match se incorporan a la lista de argumentos.
      • Si no hay un identificador después del punto, se interpreta como un sufijo de puntos de algún tipo, como una llamada indirecta a un método:
      • <.$indirecto($profundidad, $enlaces, $destino, @args)>
      • En este caso el objeto que se pasa como invocador es el estado actual del match, y se espera que el método devuelva un nuevo objeto de estado de match. Los argumentos del patrón de match adicionales $profundidad, $enlaces y $destino) se deben suministrar de forma explícita.
      • Con :keepall se evita el sistema de no captura.
    • Un $ al principio indica una subregla indirecta. La variable debe contener un objeto Regex o un string para compilarse como el regex. El string nunca hace match literalmente.
      • Si falla la compilación de la forma del string, el mensaje de error se transforma en una advertencia y la aserción falla.
      • La aserción indirecta de la subregla no se captura. (Por defecto no se captura ningúna aserción que comience con un símbolo de puntuación). Puedes capturarla siempre de forma explícita:
      • /<nombre>=$rx> /
      • Una subregla se considera declarativa si su frontal es declarativo y en la medida que la variable no cambie. El prefijo con un punto de secuencia finaliza las optimizaciones estáticas repetidas.
    • El comienzo con :: indica una subregla simbólica indirecta:
      • / <::($cualquiernombre)> /
      • El nombre de la subregla debe estar dentro de la variable. En base a las reglas de distribución única de métodos, primero se busca el nombre de la subregla en la gramática actual y en sus ancestros. Si no lo encuentra se intenta hacerlo vía MMD, en cuyo caso puede encontrar reglas definidas como múltiples en vez de como métodos. Este sistema, por defecto no captura, y siempre se considera procedimental y no declarativo.
    • Un comienzo con @ hace match como un array de barras, ahora, cada elemento es tratado como una subregla (string u objeto Regex) en vez de tratarse literalmente. Esto es, se fuerza a un string a ser compilado como una subregla en vez de hacer match literalmente. (Lo mismo ocurre con un objeto Regex).
      • Esta aserción no es capturada automáticamente.
    • El uso de un hash como una aserción está reservado.
    • Un comienzo con { indica el código que produce una expresión regular que se interpola en el patrón como una subregla en ese momento:
      • / (<.ident>) <{ %cache{$0} //= get_body_for($0) }> /
      • La ejecución está garantizada en tiempo canónico, declara un punto en la secuencia y se considera procedimental.
    • Un comienzo con & interpola el valor de retorno de una llamada a una subrutina como un regex. Así
      • <&foo()>
      • es la versión corta de
      • <{ foo() }>
      • Se considera procedimental.
    • Respecto a la interpolación y en cualquier caso, si el valor ya es un objeto Regex, no se recompila. Si es un string, la forma compilada se cachea con el string hasta la próxima vez que lo utilices (no se recompila) a menos que el string cambie. (Cualquier nombre de variable léxica externa debe rebotar). Las subreglas no se pueden interpolar sino hay cierre completo. Una subregla interpolada guarda sus resultados de match internos como un sólo elemento, por tanto sus paréntesis nunca tienen efecto fuera de los grupos de regexes. (En otras palabras, se tienen en cuenta los paréntesis de forma léxica).
    • Un comienzo con ?{ o !{ indica una aserción de código:
      • / (\d**1..3) <?{ $0 < 256 }> / / (\d**1..3) <!{ $0 < 256 }> /
      • Es similar a:
      • / (\d**1..3) { $0 < 256 o falla } / / (\d**1..3) { $0 < 256 y falla } /
      • Al contrario que las acotaciones, las aserciones de código se consideran declarativas; no garantizan la ejecución en tiempo canónico si el optimizador no puede probar si algo después no puede hacer match. Puedes utilizarlo en una llamada a una acotación no-canónica así:
      • token { foo .* <?{ do { say "Lo tengo!" } or 1 }> .* bar }
      • El bloque do no funcionará a menos que el string termine con "bar".
    • Un comienzo con [ indica una clase enumerada de caracteres. Los rangos se indican con ".." en vez de "-".
      • / <[a..z_]>* /
      • Se ignoran los espacios en blanco dentro de los corchetes:
      • / <[ a..z _ ]>* /
      • Un rango al revés es ilegal. En código directamente compilado, es un error en tiempo de compilación decir
      • / <[ z .. a ]> / # No se permite rangos al revés
      • En código compilado indirectamente, da una advertencia similar y la aserción falla:
      • $rx = '<[ z .. a ]>'; / <$rx> /; # advierte y nunca hace match
    • Un comienzo con - indica una clase complementada de caracteres:
      • / <-[a..z_]> <-alpha> / / <- [a..z_]> <- alpha> / # permite espacio en blanco seguido después de -
      • Esencialmente es lo mismo que utilizar el símbolo de admiración y el punto:
      • / <![a..z_]> . <!alpha> . /
      • Se ignoran los espacios en blanco después del primer -.
    • Un comienzo con + también puede indicar que la clase de caracter que sigue ha de realizar match en un sentido positivo.
      • / <+[a..z_]>* / / <+[ a..z _ ]>* / / <+ [ a .. z _ ] >* / # se permite espacio en blanco después de +
    • Las clases de caracteres pueden ser combinadas (poniendo o quitando) dentro de un sólo conjunto de corchetes. Se ignoran los espacios en blanco. Por ejemplo:
      • / <[a..z] - [aeiou] + xdigit> / # consonante o dígito hex
      • Se puede utilizar una clase de caracter por su nombre:
      • <alpha>
      • Sin embargo, para combinar clases debes añadir un prefijo al nombre de la clase del caracter con + o -. Se requiere un espacio en blanco antes de cualquier - pues podría malinterpretarse como un extensor de un identificador.
    • La aserción especial <.> hace match de cualquier grafema lógico (incluyendo secuencias de caracteres Unicode combinados):
      • / buscaen = <.> / # Puede ser un char combinado
      • Es lo mismo que:
      • / buscaen = [:graficos .] /
    • Un comienzo con ! significa una negación (siempre es una aserción de ancho-cero):
      • / <!before _ > / # No estamos antes que _
      • Ten en cuenta que <!alpha> es distinto que <-alpha>. /<-alpha>/ es una clase de caracter complementaria equivalente a /<!before <alpha>> ./, donde <!alpha> es una aserción de ancho-cero equivalente a la aserción /<!before <alpha>>/.
      • Ten en cuenta también que el metacaracter ! no cambia las reglas de interpretación de lo que sigue (al contrario que + o -).
    • Un comienzo con ? indica una aserción positiva de ancho-cero, y ! reinterpreta el resto de la aserción recursivamente como si ? no estuviera ahí. Adicionalmente y para forzar el ancho-cero, también suprime cualquier captura con nombre:
      • <alpha> # hace match de una letra y captura en $alpha (eventualmente $<alpha>) <.alpha> # hace match de una letra y no captura <?alpha> # hace match de null antes de una letra y no captura
      • Las aserciones con nombres especiales incluyen:
      • / <?before patrón> / # lookahead / <?after patrón> / # lookbehind
      • / <?same> / # verdadero entre dos caracteres idénticos
      • / <.ws> / # hace match de un "espacio en blaco": # \s+ si está entre dos caracteres \w, # \s* cualquier otro caso
      • / <?at($pos)> / # hace match sólo en una posición string en particular # versión corta de <?{ .pos === $pos }> # (se considera declarativa hasta que $pos cambie)
      • Se puede utilizar cualquiera de estas aserciones como capturas con nombre omitiendo la puntuación frontal. Sin embargo, la captura implica más memoria y tiempo de computación, y por tanto puede ser normal que omitas los datos que no quieras preservar.
      • La aserción after implementa un lookbehind para buscar cosas en orden inverso en el árbol de sintaxis. Es ilegal realizar un lookbehind en un patrón que no pueda ser reversible.
      • Nota: se puede conseguir el efecto de un escaneo hacia adelante de lookbehind en el nivel más superior con:
      • / .*? premovida <( patrónprincipal )> /
    • Los tokens especiales <...>, <???> y <!!!> tienen el mismo significado que "todavía sin definir" en los regexes de código ordinario donde hay elipses de barras. (Sin embargo, debido a las reglas recursivas de antes, <!!> es equivalente a <?> y hace match con un string null. Igualmente, <!!before x> es como <?before x> excepto que es ignorado por un matcher de token largo).
    • Un comienzo con * indica que el patrón a continuación permite un match parcial. Esto siempre sucede después de hacer match con el máximo de caracteres posible. (No es ancho-cero a menos que hagan match 0 caracteres). Por ejemplo, para hacer match en una serie de abreviaciones, puedes escribir cualquiera de estas líneas:
      • s/ ^ G<*n|enesis> $ /gen/ o s/ ^ Ex<*odus> $ /ex/ o s/ ^ L<*v|eviticus> $ /lev/ o s/ ^ N<*m|umbers> $ /num/ o s/ ^ D<*t|euteronomy> $ /deut/ o ...
      • / (<* <foo bar baz> >) /
      • / <short=*@abbrev> / y devuelve %long{$<short>} || $<short>;
      • El patrón está restringido a formas declarativas que puedan ser escritas de nuevo como matches de caracteres opcionales anidados. Si todos los caracteres son opcionales hay que tener en cuenta la información de secuencia. No es suficiente reescribir:
      • <*xyz>
      • como:
      • x? y? z? # mal, puede permitir xz
      • En vez de eso, debe implementarse como:
      • [x [y z?]?]? # sólo permite x, xy, xyz (y '')
      • Se permiten cuantificadores explícitos por caracter, esto es:
      • <* a b+ c | ax*>
      • es reescrito como algo parecido a:
      • [a [b+ c?]?]? | [a x*]?
      • En el último ejemplo asumimos que el matcher del token DFA nos va a dar el match más largo cueste lo que cueste. También es posible que las secuencia de múltiples caracteres puedan remapearse recursivamente:
      • <* 'ab'+> # hace match con a, ab, ababa, etc. (¡pero no con aab!) ==> [ 'ab'* <*ab> ] ==> [ 'ab'* [a b?]? ]
      • [Conjetura: dependiendo de lo chulos que seamos, podemos (o no) ser capaces de autodetectar ambiguedades en <*abbrev> y no generar abreviaciones (siempre se debe permitir el match exacto de una abreviación corta, incluso si es el prefijo de una abreviación larga). Si esto no es posible, el usuario deberá comprobar la existencia de ambiguedades después del match. También hay que tener en cuenta la presunción de que la forma del array no cambie mucho. Si cambia mucho, el matcher de token largo tendrá que recalcularse, lo que sería demasiado costoso].
    • Un comienzo con <~~> indica en la regla actual, que alguna o todas las llamadas sean recursivas hacia atrás. Un argumento opcional indica cual subpatrón se reutilizará (sólo se resolverá un único subpatrón). Si se omite, se realiza una llamada recursiva a todo el patrón:
      • <~~> # me llamo a mí mismo recursivamente <~~0> # hace match en base al patrón de $0 <~~foo> # hace match en base al patrón de $foo
      • Esto repite el match en el patrón asociado con el nombre, no con el match del string. Por tanto
      • $_ = "foodbard"
      • / ( foo | bar ) d $0 / # falla; no hace literal con "foo" / ( foo | bar ) d <$0> / # falla; no hace match con /foo/ como una subregla / ( foo | bar ) d <~~0> / # hace match utilizando la regla asociada con $0
      • El último es equivalente a
      • / ( foo | bar ) d ( foo | bar ) /
      • Fíjate que la llamada "self" de
      • / <term> <operator> <~~> /
      • realiza una llamada hacia atrás como una subregla dentro de esta regla anónima y se ancla de forma implícita al final del operador como cualquier otra subregla. A pesar de que la regla externa comprueba el string, la llamada interna no lo hace.
      • Una consecuencia de la sección anterior es que también puedes conseguir que
      • <!~~>
      • sea gratis, y fallará si la regla actual puede hacer match otra vez en esta ubicación.

Los siguientes tokens incluyen los símbolos mayor que/menor que pero no requieren balanceo:

    • Un token <( indica el comienzo de la captura total del match, mientras que el correspondiente token )> indica su punto final. Cuando se produce el match, el comportamiento de las aserciones siempre es verdadero, pero tiene el efecto secundario de los atributos .from y .to del objeto del match. Por tanto:
      • / foo <( \d+ )> bar /
      • es equivalente a:
      • / <?after foo> \d+ <?before bar> /
      • excepto que la comprobación de "foo" puede realizarse hacia adelante, mientras que una aserción lookbehind podría presumíblemente comprobar \d+ y entonces hacer match de "foo" hacia atrás. El uso de <(...)> afecta sólo al significado de las posiciones del comienzo y fin del match, y todo se calcula en base a esas posiciones. Por ejemplo, después del match $() sólo hay los dígitos que hacen match, y $/.to apunta a lo que hay después de esos dígitos. Otras capturas (nombradas o numeradas) no están afectadas y se pueden acceder a ellas mediante $/.
      • Estos tokens se consideran declarativos, y pueden ser forzados para hacer backtracking.
    • Un token « o << indica el límite izquierdo de una palabra. Un token » o >> indica el límite derecho de una palabra (al igual que los tokens independientes, no necesitan balancearse). El \b de Perl 5 es sustituido por la aserción "límite de palabra" <?wb>, mientras que \B ahora es <!wb> (nada de esto depende de la definición de <!wb>, excepto en la definición de caracteres "palabra").

Subreglas Predefinidas

Estas son las subreglas predefinidas para cualquier gramática o regex:

    • ident >>
      • Hace match de un identificador.
    • upper >>
      • Hace match de un sólo caracter en mayúsculas.
    • lower >>
      • Hace match de un sólo caracter en minúsculas.
    • alpha >>
      • Hace match de un sólo caracter alfabético.
    • digit >>
      • Hace match de un sólo dígito.
    • xdigit >>
      • Hace match de un sólo dígito hexadecimal.
    • print >>
      • Hace match de un sólo caracter imprimible.
    • graph >>
      • Hace match de un caracter "gráfico".
    • cntrl >>
      • Hace match de un sólo caracter de "control". Un caracter de control normalmente es el que produce salidas de control del terminal, por ejemplo, newline y backspace son caracteres de control. Todos los caracteres con ord() menos de 32 normalmente están clasificados como caracteres de control (asumiendo ASCII, los conjuntos de caracteres ISO Lation y Unicode) y también el que tiene un ord() de 127 (DEL ).
    • punct >>
      • Hace match de un sólo caracter de puntuación.
    • alnum >>
      • Hace match de un sólo caracter alfanumérico. Es equivalente a <+alpha +digit> .
    • wb >>
      • Devuelve un match de ancho-cero que se cumple dentro de una palabra. El contenido de una palabra es un punto que tiene un "\w" a un lado y un "\W" en el otro (en cualquier orden), contando con el principio y el final del string para hacer match con "\W".
    • ww >>
      • Hace match entre dos caracteres de palabra (match de ancho-cero).
    • ws >>
      • Hace match de los espacios en blanco requeridos entre dos caracteres de palabra, en caso contrario hace match de los espacios en blanco opcionales. Es equivalente de forma tosca a <!ww> \s* (ws no es requerido para la subregla ww).
    • space >>
      • Hace match de un sólo caracter de espacio en blanco (igual que \s ).
    • blank >>
      • Hace match de un caracter "en blanco" -- en la mayoría de los casos se corresponde con el espacio y el tabulador.
    • before pattern >>
      • Hace un lookahead -- por ejemplo, comprueba si estamos en una posición donde hace match patrón. Si así es, devuelve un objeto Match de ancho-cero.
    • after pattern >>
      • Hace un lookbehind -- por ejemplo, comprueba si el string que tenemos antes de la posición actual hace match con <patrón> (anclado al final). Si así es, devuelve un objeto Match de ancho-cero.
    • <?> >>
      • Hace match de un string NULL, es decir, siempre devuelve true.
    • <!> >>
      • Al revés que <?>, es decir, siempre devuelve false.

Reforma del backslash

    • Las propiedades \p y \P ahora son reglas gramáticas intrínsecas como (<alpha> y <-alpha>). Pueden ser combinadas utilizando la notación de clase de caracter mencionada antes: <[_]+alpha+digit>. Independientemente de los nombres de las clases de caracter, las propiedades Unicode siempre están disponibles con el prefijo is. Por tanto, <+isLu+isLt> es equivalente a <+upper+title>. Si defines una propiedad "is", ocultará cualquier propiedad Unicode con el mismo nombre.
    • Ya no existen las secuencias \L...\E, \U...\E, y \Q...\E. En los casos raros que las necesites, puedes utilizar <{ lc $regex }>, etc.
    • Ya no existe la secuencia \G, que es sustituida por :p. Sin embargo, no tiene sentido utilizar :p dentro de un patrón porque cada patrón interno está anclado de forma implícita a la posición actual. Consulta la aserción at más abajo.
    • Las referencias hacia atrás (por ej. \1, \2, etc.) ya no existen, y se sustituyen por $0, $1, etc. porque las variables ya no se interpolan.
      • Se asume que las variables numéricas cambian cada vez y por tanto se consideran procedimentales, no como las variables normales.
    • Las nuevas secuencias backslash, \h y \v, hacen match con el espacio en blanco horizontal y vertical respectivamente, Unicode incluido.
    • \s ahora hace match con cualquier caracter de espacio en blanco Unicode.
    • La nueva secuencia backslash \N hace match con todo menos con una nueva línea lógica. Es la negación de \n.
    • Otras secuencias backslash en mayúsculas también son la negación de sus correspondientes en minúsculas:
        • \H hace match con todo menos con el espacio en blanco horizontal.
        • \V hace match con todo menos con el espacio en blanco vertical.
        • \T hace match con todo menos con tab.
        • \R hace match con todo menos con return.
        • \F hace match con todo menos con un formfeed.
        • \E hace match con todo menos con un escape.
        • \X... hace match con todo menos con el caracter especificado (en hexadecimal).

Ahora las regexes son un lenguaje de clase principal, no de strings

    • Ya no existe el constructor regex qr/pattern/ de Perl 5.
    • Los equivalentes en Perl 6 son:
      • regex { patrón } # siempre toma {...} como delimitadores rx / patrón / # al menos puede tomar cualquier char como delimitador
      • No puedes utilizar espacios en blanco o caracteres alfanuméricos como delimitadores. El espacio es opcional a menos que necesites distinguir entre argumentos de modificadores o funciones entre paréntesis. Por tanto, puedes utilizar paréntesis como delimitadores de rx, pero sólo si pones en medio un espacio en blanco:
      • rx ( patrón ) # ok rx( 1,2,3 ) # intenta llamar a la función rx
      • (En Perl 6 esto se cumple en todas las construcciones que acoten algo.)
    • Si utilizas modificadores, éstos tienen que ir antes del delimitador de apertura:
      • $regex = regex :g:s:i { mi nombre es (.*) }; $regex = rx:g:s:i / mi nombre es (.*) /; # lo mismo
      • Entre el último modificador y el delimitador de apertura tienes que dejar un espacio, porque sino, el delimitador de apertura puede ser tomado como un argumento del modificador.
    • No puedes utilizar los dos puntos como delimitador. Se permite el espacio entre modificadores:
      • $regex = rx :g :s :i / mi nombre es (.*) /;
    • El nombre del constructor qr cambió porque ya no es un operador que acote algo y pueda interpolarse. rx es la abreviación de regex, (no confundir con expresiones regulares, menos cuando sí lo sean).
    • Como indica la sintaxis, ahora se parece más al constructor sub {...}. De hecho, es mucho más parecido en Perl 6.
    • Como {...} ahora es siempre un acotamiento (que todavía puede ejecutarse en ciertos contextos y ser un objeto en otros), un /.../ ahora también siempre es un objeto Regex (que todavía puede hacer match de forma inmediata en ciertos contextos y ser un objeto en otros).
    • En concreto, un /.../ hace match de forma inmediata en un contexto de valores (void, Boolean, string o numérico), o cuando es un argumento explícito de ~~. En cualquier otro caso es un constructor Regex idéntico a la forma regex. Esto es:
      • $var = /patrón/;
      • ya no hace match y pone $var en el resultado. En cambio, asigna un objeto Regex a $var.
    • Los dos casos siempre pueden distinguirse utilizando m{...} o rx{...}:
      • $match = m{patrón}; # Inmediatamente hace match regex, asigna el resultado $regex = rx{patrón}; # Asigna la expresión de regex a sí mismo
    • Esto significa que mágicamente tiene otros usos como:
      • @lista = split /patrón/, $str;
      • tiene las mismas consecuencias que la semántica normal.
    • Tambien ahora es posible crear una subrutina definida por el usuario que actúe como grep:
      • sub my_grep($selector, *@list) { given $selector { when Regex { ... } when Code { ... } when Hash { ... } # etc. } }
      • Cuando llamas a my_grep, el primer argumento está dentro del contexto del item, por tanto pasar {...} o /.../ produce un objeto Code o un objeto Regex elegido por el switch. (El grep normal permite que haga todo el trabajo un operador de match inteligente).
    • La declaración regex tiene variantes igual que rx. Concretamente hay dos variantes especiales para uso gramatical: token y rule.
      • Una declaración token:
      • token ident { [ <alpha> | _ ] \w* }
      • por defecto nunca hace backtrack, esto es, es fiel a lo que ha analizado hasta ahora. Lo anterior es equivalente a
      • regex ident { [ <alpha>: | _: ]: \w*: }
      • pero más sencillo de leer. Los cuantificadores crudos *, + y ? nunca hacen backtrack en un token. En regex normales utiliza *:, +: o ?: para evitar cualquier backtracking dentro del cuantificador. Si quieres hacer backtrack de forma explícita, agrega un ? o un ! al cuantificador. ? fuerza a un matching al mínimo como de costumbre, mientras que ! fuerza un matching más ámplio. La declaración token realmente es la abreviación de
      • regex :ratchet { ... }
      • Otra cosa es la declaración rule, para declarar cosas no-terminales en una gramática. Al igual que token, no hace backtrack por defecto. Además, un regex rule también asume :sigspace. Un rule realmente es la abreviación de:
      • regex :ratchet :sigspace { ... }
    • La sintaxis de Perl 5 ?...? (se cumple una vez), no suele utilizarse y puede emularse de una forma más clara con la variable state:
      • $resultado = do { state $x ||= m/ patrón /; } # sólo hace match la primera vez
      • Para inicializar el patrón, simplemente pon $x = 0. Si quieres que $x sea visible no puedes usar bloques:
      • $resultado = state $x ||= m/ patrón /; ... $x = 0;

Control de Backtracking

Puedes controlar el backtracking dentro de las porciones de un patrón consideradas procedimentales y no declarativas.

    • Por defecto el backtracking hace match amplios en rx, m, s y parecidos, al igual que en declaraciones regex ordinarias. En declaraciones rule y token el backtracking debe ser explícito.
    • Para forzar un backtracking corto a la unidad precedente, agrega un :? o un ? a la unidad. Si el token precedente es un cuantificador, puede omitirse :, por tanto *? funciona igual que en Perl 5.
    • Para forzar a la unidad precedente a realizar un backtracking amplio en una parte (no es por defecto), agrega un :! a la unidad. Si el token precedente es un cuantificador, puede omitirse : (Perl 5 no tiene los constructores correspondientes porque el backtracking siempre es amplio por defecto).
    • Para forzar a la unidad precedente a no realizar backtracking, utiliza un sólo : sin el ? o ! a su derecha. Realizar un backtracking sobre un sólo símbolo de dos puntos provoca que el motor regex no lo intente de nuevo en la unidad precedente:
      • mm/ \( <expr> [ , <expr> ]*: \) /
      • (por ej. si no hay un cierre de paréntesis cerca, no hay un punto intentando hacer match de <expr>).
      • Para forzar a todas las unidades en una expresión a no realizar backtrack por defecto, utiliza :ratchet o rule o token.
    • Hacer un backtracking sobre dos puntos dobles provoca un fallo inmediato sobre los grupos inmediatos (normalmente se trata de un grupo de alternaciones):
      • mm/ [ if :: <expresión> <bloque> | for :: <lista> <bloque> | loop :: <controles_loop>? <bloque> ] /
      • (por ej. no existe un punto que intente hacer match de una palabra clave distinta si ya se encontró una pero falló). Ten en cuenta que todavía puedes ir hacia atrás dentro de la alternación, y puedes deshabilitarla colocándole un : después. Si un :ratchet explícito o implícito deshabilitó el backtracking mediante un : implícito y si la primera toma falla, necesitas poner un ! explícito después de la alternación para poder ir hacia atrás dentro de otra alternación.
      • :: también provoca el ocultamiento de cualquier string que no cambie y que esté a la derecha del "token más largo" procesado mediante |. Para tener una constancia inicial, sólo se evalúa la parte izquierda.
    • Un backtracking con el símbolo de dos puntos tres veces produce que el regex actual falle completamente (da igual donde ocurra dentro del regex):
      • regex ident { ( [<alpha>|_] \w* ) ::: { fail if %reserved{$0} } || " [<alpha>|_] \w* " }
      • mm/ get <ident>? /
      • (no se permite el uso de una palabra reservada sin acotar como identificador)
    • Un backtracking sobre una aserción <commit> provoca que el match entero falle completamente, sin importar cuantas subreglas se utilizaron:
      • regex subname { ([<alpha>|_] \w*) <commit> { fail if %reserved{$0} } } mm/ sub <subname>? <block> /
      • (utilizar una palabra reservada como nombre de subrutina produce un fallo instantáneo que también afecta al match)
      • Si se da un commit como argumento, éste será el nombre de una regla de llamada que será procesada por commit:
      • <commit('infix')>
    • Una aserción <cut> siempre cumple los matches que hace, y tiene el efecto secundario lógico de eliminar las partes del string que hayan realizado match. Esto libera memoria inmediatamente y dependerá de las diferentes interacciones entre sus backreferences, la implementación del string y el recolector de basura. En cualquier caso, el string aparecerá cortado al principio. No se permite utilizar <cut> en un string donde no tengas acceso de escritura.
      • Utilizar <cut> con un backtrack en pasado provoca el fallo completo del match (también pasa con <commit>). Esto ocurre porque ahora no hay un texto precedente al backtrack. Esto es útil para descartar entrada procesada cuando se hace match de un stream de entrada o cuando se hace match de un iterador de longitud arbitraria.

Rutinas Regex, con Nombre y Anónimas

    • Las analogías entre sub y regex son muchas.
    • Tantas como que puedes tener subs con nombre y subs anónimas...
    • ... y también puedes tener regexes con nombre y regexes anónimos (y tokens y reglas):
      • token ident { [<alpha>|_] \w* }
      • # y después...
      • @ids = grep /<ident>/, @strings;
    • Como el ejemplo anterior indica, es posible referirse a regexes con nombre:
      • regex numero_serie { <[A..Z]> \d**8 } token type { alpha | beta | production | deprecated | legacy }
      • y en otros regexes como aserciones con nombre:
      • rule identificacion { [soft|hard]ware <type> <numero_serie> }
      • Estos regexes con declaraciones de palabras clave son oficialmente de tipo Method, derivado de Routine.
      • Normalmente, el contexto controla el anclaje de cualquier llamada a una subregla. Cuando un regex, token o método de regla se llama como una subregla, el principio está anclado a la posición actual (como con :p) y el final no está anclado debido a que es probable que el contexto de llamada quiera continuar con el parseo. Sin embargo, cuando éste método directamente hace un match corto, automáticamente quedan anclados ambos extremos al principio y al final del string. Así, puedes hacer un matching de un patrón directamente utilizando una rutina regex anónima como un sólo patrón:
      • $string ~~ regex { \d+ } $string ~~ token { \d+ } $string ~~ rule { \d+ }
      • y esto equivale a
      • $string ~~ m/^ \d+ $/; $string ~~ m/^ \d+: $/; $string ~~ m/^ <.ws> \d+: <.ws> $/;
      • La regla básica general es que los métodos definidos con palabras clave hacen .*? de forma implícita, como el escaneo, mientras que las acotaciones como m// y s// hacen tal escaneo sin utilizar anclajes explícitos.
      • Las formas rx// y // pueden escanear cuando se utilizan directamente dentro de un match inteligente o en un contexto booleano, o no escanear cuando son llamadas indirectamente como una subregla. Esto es, el objeto devuelto por rx// se comporta como m// cuando se utiliza directamente, y se parece a regex {} cuando se utiliza como una subregla:
      • $patron = rx/foo/; $string ~~ $patron; # equivale a m/foo/; $string ~~ /'[' <$patron> ']'/ # equivale a /'[foo]'/

Nada es ilegal

    • Los patrones vacíos ahora son ilegales.
    • Para hacer match de cualquier cosa antes de que el regex complete el match, utiliza:
      • / <prior> /
    • Para hacer match de un string de ancho-cero, debes utilizar alguna representación explícita del match null:
      • / '' /; / <?> /;
      • Por ejemplo:
      • split /''/, $string
      • hace cortes entre caracteres, igual que esto:
      • split '', $string
    • Igualmente, para hacer match de una alternativa vacía, utiliza algo como:
      • /a|b|c|<?>/ /a|b|c|''/
      • Esto hace más fácil capturar errores como este:
      • /a|b|c|/
      • Un caso especial: la primera alternativa null en un match como
      • mm/ [ | if :: <expr> <block> | for :: <list> <block> | loop :: <loop_controls>? <block> ] /
      • simplemente se ignora. De esta forma sólo la primera alternativa es especial. Si escribes:
      • mm/ [ if :: <expr> <block> | for :: <list> <block> | loop :: <loop_controls>? <block> | ] /
      • todavía persistirá el error.
    • Sin embargo, no se produce el error en construcciones sintácticas no-null para tener un matching degenerado del string null:
      • $algo = ""; /a|b|c|$algo/;
      • En concreto, <?> siempre hace match de un string null, y <!> siempre falla al hacer match con lo que sea.

Matching de tokens largos

En vez de representar alternaciones temporales, | ahora representa una alternación lógica con semánticas de token-largo declarativas. (Ahora puedes usar || para indicar la alternación temporal antigua. Esto es, | y || ahora funcionan dentro de la sintaxis regex igual que si lo hacen fuera de la sintaxis regex, donde representan una unión y corto-circuito OR. Esto quiere decir que hay una ligera precedencia de | sobre ||).

Históricamente el procesamiento regex en Perl procede de un algoritmo NFA de backtracking. Esto es muy poderoso, pero muchos parsers son más eficientes procesando reglas en paralelo que una detrás de otra, al menos desde arriba hasta un punto. Si ves algo parecido a la gramática yacc, encontrarás un montón de declaraciones patrón/acción donde los patrones son considerados en paralelo, y algunas veces la gramática decide cual acción descartar. Mientras que el punto de vista de Perl por defecto es hacer un parsing arriba-abajo (quizás con una capa intermedia desde el fondo hacia arriba para manejar la precedencia de operadores), es extremadamente más fácil de entender para el usuario si al menos el procesamiento de tokens es determinístico. Por tanto, para propósitos donde se realizan matching en los regex, definimos un patrón para tokens como en los patrones que pueden hacer match sin efectos secundarios potenciales o sin autoreferencia. (Debido a que los espacios en blanco a menudo tienen efectos secundarios en la transición de líneas, normalmente se omiten de este tipo de patrones, dando o tomando un pequeño lookahead). Básicamente, Perl deriva automáticamente un lexema desde la gramática sin que tengas que escribir uno.

Con ese fin, cada regex en Perl 6 requiere que pueda distinguir sus patrones "puros" de sus acciones, y devolver su lista de patrones de tokens iniciales (de forma transitiva incluyendo los patrones de tokens de cualquier subregla llamada por la parte "pura" del regex, sin incluir más de una subregla para evitar la autoreferencia, la cual no está permitida en las expresiones regulares tradicionales). Una alternación lógica utilizando | toma dos o más de esas listas y distribuye a las alternativas que hacen match con el prefijo de token más largo. Esto puede o no puede ser la alternativa que viene primero de forma léxica.

Sin embargo, si dos alternativas hacen match en la misma longitud, el empate se rompe a favor de la más específica. La alternativa que comience con el string más largo gana; esto es, un match exacto está más cerca que un match que utiliza clases de caracteres. Si esto no funciona, el empate se rompe mediante uno de dos métodos. Si las alternativas están en gramáticas distintas, el MRO estandar (orden de resolución de métodos) determina cual probar primero. Si las alternativas están en el mismo archivo de gramáticas, toma la preferencia la alternativa que esté antes textualmente. (Si las reglas gramaticales están definidas en más de un archivo, el orden no se define, y se debe utilizar una aserción explícita para forzar el fallo si primero se utiliza la equivocada).

Este prefijo de token largo corresponde de forma ruda con la noción de "token" en otros sistemas de parseo que utilizan un lexema, pero en el caso de Perl esto es un fenómeno añadido derivado de forma automática de la definición de la gramática. Sin embargo y a pesar del cálculo automático, el usuario puede modificar el conjunto de tokens; varios constructores que estén dentro de un regex declarativo le dicen al motor gramatical que han finalizado con la parte del patrón y comienzan en uno de los efectos secundarios, por tanto, el usuario controla lo que es un token insertando estos constructores. Los constructores consideran la finalización de la declaración de un token y comienzan la parte "acción" del patrón incluyendo:

    • Cualquier :: o ::: control de backtracking (pero no el modificador posesivo :).
    • Cualquier unidad cuantificada con un match mínimo (utilizando el modificador ?).
    • Cualquier acción {...}, pero no una aserción que contenga una acotación. La forma acotada del cuantificador general **{...} finaliza el token más largo, las formas sin acotar no.
    • Cualquier operador de control de flujo secuencial como || o &&.
    • La consecuencia del punto anterior, debido a la gramática estandar de la regla <ws> que define espacios en blanco mediante ||, es que el token más largo también finaliza en cualquier parte de la regex o de la regla que pueda hacer match con el espacio en blanco usando tal regla, incluyendo espacios en blanco que hagan match de forma implícita mediante :sigspace. (Sin embargo, las declaraciones de token pueden reconocer espacios en blanco dentro de un token utilizando primitivos a bajo nivel como \h+ u otras clases de caracter).

Los subpatrones (capturas) concretamente no finalizan el patrón del token, pero requiere un reparseo del token para encontrar la ubicación de los subpatrones. Igualmente, las aserciones pueden necesitar comprobación después que se determina el token más largo. (De forma alternativa, si las semánticas DFA se simulan de alguna manera, como el NFA Thompson, es posible saber cuando descartar aserciones sin comprobaciones hacia atrás).

Los cuantificadores de match amplio y las clases de caracter no finalizan un patrón de token, así como las aserciones de ancho-cero como los límites de palabra.

Debido a que estas aserciones pueden formar parte de un token, el motor de lexemas debe ser capaz de recuperarse de un fallo de la aserción y hacer backtrack hasta el próximo mejor candidato del token, que deberá ser menor o de la misma longitud, pero nunca mayor que la del candidato actual.

Para un patrón que comience con una aserción lookahead positiva, se asume que la aserción es más específica que el subsiguiente patrón, por tanto, el patrón del lookahead es tratado como el token más largo; el matcher del token más largo será lo suficientemente inteligente como para hacer match de nuevo en algún texto que pueda estar a lo largo del lookahead cuando (y si) continúa el match.

Curiosamente, la palabra clave concreta token no determina el alcance de un token, excepto en la medida que el patrón del token no haga muchos matches normalmente de espacios en blanco. Como contraste, la palabra clave rule (que asume :sigspace) define un patrón que tiende a descalificarse así mismo en el primer espacio en blanco. Por tanto, la mayoría de los patrones de token finalizarán cuando vengan las declaraciones token. Por ejemplo, una declaración de token como

token lista_compositores { \[ <expr> \] }

considera su "token más largo" el corchete izquierdo, debido a que la primera cosa que hará la regla expr será atravesar espacios en blanco opcionales.

El matcher de token inicial debe tener en cuenta las mayúsculas/minúsculas (o cualquier otra canonicación primitiva) y hacer lo correcto incluso cuando afecte a la propagación de reglas que no tengan la misma canonicación. Esto es, deben continuar representando el conjunto de matches donde la regla más cercana pueda hacer match.

La forma || tiene la semántica vieja de cortocircuito y no intentará hacer match de la parte derecha a menos que agote todas las posibilidades en la parte izquierda (incluyendo todas las posibilidades de |). El primer || en un regex hace que los patrones del token de la izquierda estén disponibles al matcher externo de token más largo, pero oculta cualquier comprobación posterior en el matching del token más largo. Cada || establece un nuevo matcher de token largo. Esto es, si utilizas | en la parte derecha de ||, la parte derecha establece un nuevo alcance de nivel superior para el procesamiento de tokens largos en esta subexpresión y en cualquier subregla llamada. La parte izquierda de || no ve a la parte derecha de la automatización del token más largo, al igual que la parte externa del regex que contenga ||.

Valores de retorno de los matches

Objetos Match

    • Un match siempre devuelve un objeto Match, y siempre está disponible como $/, que es una léxica contextual declarada fuera de la subrutina que llama al regex. (Un regex declara su propia variable léxica $/, y siempre se refiere al submatch más reciente dentro de la regla, si la hay). El estado actual del match se guarda en la variable del regex y eventualmente se procesará dentro de la variable de usuario $/ cuando finalize el match.
    • Como noción, un objeto match contiene (entre otras cosas) un valor booleano que indica si todo ha ido bien, un array ordenado de objetos de submatch, y un hash de nombres de objetos de submatch. (Opcionalmente también puede llevar un objeto abstracto que se utilice normalmente para construir un árbol de sintaxis abstracta). Para acceder correctamente a estos valores, el objeto match realiza evaluaciones distintas en contextos distintos:
        • En el contexto booleano se evalúa como verdadero o falso (por ej. ¿finalizó con éxito el match?):
          • if /patron/ {...} # o: /patron/; if $/ {...}
          • Se permite que el valor booleano de retorno del primer match sea verdadero con :global o :overlap o :exhaustive. El objeto Match puede producir el resto de resultados de una forma más débil si se evalúan en un contexto de lista.
        • En contexto string se evalúa el valor convertido a string de su match, que normalmente es el string completo que hace match:
          • print %hash{ "{$texto ~~ /<.ident>/}" }; # o de forma equivalente: $texto ~~ /<.ident>/ && print %hash{~$/};
          • Normalmente tendrás que decir ~$/ si quieres decir ~$/.
        • En contexto numérico se evalúa el valor numérico de su match, que normalmente es el string completo que hace match:
          • $suma += /\d+/; # o de forma equivalente: /\d+/; $suma = $suma + $/;
        • Cuando utilices un escalar, un objeto Match se evalúa a sí mismo.
          • Sin embargo, a veces puedes querer que un valor escalar alternativo se tenga en cuenta a lo largo del match. El objeto Match describe un árbol de parseo concreto para sí mismo, por tanto, este valor extra es llamado un objeto abstracto; que figura como un atributo del objeto Match. El método .ast devuelve por defecto un valor no definido. $() es una abreviación de $($/.ast).
          • Por tanto $() normalmente es el string completo del match, pero puedes quitarle prioridad llamando a make dentro de un regex:
          • my $alce = $(m:{ <cuerno> <cuerpo> { make Alce.new( cuerpo => $<cuerpo>.attach($<cuerno>) ) } # el match finaliza con éxito -- ignora el resto del regex });
          • Esto pone el nuevo nodo abstracto dentro de $/.ast. Un nodo AST puede ser de cualquier tipo. Esto hace conveniente construir árboles de sintaxis abstractos de tipos de nodos arbitrarios.
        • También puedes capturar un subconjunto del match utilizando el constructor <(...)>:
          • "foo123bar" ~~ / foo <( \d+ )> bar / say $(); # muestra 123
          • En este caso el objeto abstracto siempre es un string cuando hace un matching de string, y una lista de uno o más elementos cuando hace un matching de una lista. Esta construcción no asigna el atributo .ast.
        • Cuando se utiliza como un array, el objeto Match pretende ser un array de todas sus capturas posicionales. Por tanto
          • ($key, $val) = mm/ (\S+) => (\S+)/;
          • también puede escribirse como:
          • $resultado = mm/ (\S+) '=>' (\S+)/; ($key, $val) = @$resultado;
          • Para conseguir una sóla captura dentro de un string, utiliza un subscript:
          • $mystring = "{ mm/ (\S+) '=>' (\S+)/[0] }";
          • Para que todas las capturas estén en un string, utiliza []:
          • $mystring = "{ mm/ (\S+) '=>' (\S+)/[] }";
          • O ponlas en un array:
          • $mystring = "@( mm/ (\S+) '=>' (\S+)/ )";
          • Ten en cuenta que $/ es una variable escalar que no se adapta en un contexto de lista. Utiliza @() como una abreviación de @($/) para adaptar las capturas posicionales bajo el contexto de lista. Se permite que un objeto Match evalúe perezosamente su match en un contexto de lista. Utiliza eager @() para forzar un match rápidamente.
        • Cuando se utiliza como un hash, un objeto Match pretende ser un hash de todos sus nombres de capturas. Los keys no incluyen sigils, por tanto si capturas en la variable @<foo>, su nombre real es $/{'foo'} o $/<foo>. Sin embargo, todavía puedes referirte a ello como @<foo> en cualquier lugar donde $/ sea visible (pero es un error utilizar el mismo nombre para dos tipos de datos de captura distintos).
          • Ten en cuenta que $/ es una variable escalar que no se adapta en un contexto de lista. Utiliza %() como una abreviación de %($/) para adaptarlo a un hash, o mapealo a una variable del tipo apropiado. Al igual que @(), también es posible para %() producir sus pares perezosamente en un contexto de lista.
        • Las capturas numeradas pueden tratarse como nombres, por tanto $<0 1 2> equivale a $/[0,1,2]. Esto te permite escribir trozos de mezclas de capturas con nombre y capturas numeradas.
        • En código ordinario, las variables $0, $1, etc. son alias dentro de $/[0], $/[1], etc. No serán definidas si falla el último match (a menos que no utilicen la palabra clave let y estén explícitamente dentro de una acotación).
    • Los objetos Match tienen métodos que dan más información sobre el match. Por ejemplo:
      • if m/ def <ident> <codeblock> / { say "Encontrada definición de subrutina desde $/.from.bytes ", "hasta $/.to.bytes"; }
      • Los métodos definidos son
      • $/.from # la posición inicial del match $/.to # la posición final del match $/.chars # $/.to - $/.from $/.orig # el string del match original $/.Str # substr($/.orig, $/.from, $/.chars) $/.ast # el resultado abstracto asociado con este nodo $/.caps # las capturas secuenciales $/.chunks # la conversión a tokens secuenciales
      • Dentro de un regex, el estado actual del match también da
      • .pos # la posición actual del match
      • Este último valor puede corresponderse con $¢.from o $¢.to dependiendo de si el match va hacia adelante o hacia atrás (este caso surge dentro de una aserción <?after ...>).
    • Como hemos visto, un Match en contexto de lista devuelve sus capturas posicionales. Sin embargo, a veces puedes querer una lista adaptada de tokens en el mismo orden que ocurren en el texto. El método .caps devuelve una lista de cada captura en orden, independientemente si son capturas de nombres o numeradas (aparte del orden, no hay más información; todos los elementos de la lista son los mismos objetos Match que pueda haber en otro sitio). Las correspondencias se devuelven en pares clave/valor donde la clave es el nombre o número donde el objeto hizo match, y el valor es el objeto del match en sí.
      • Además de la devolución de estos objetos Match de captura, el método .chunks también devuelve el "ruido" que hay entre las capturas. Al igual que .caps, la lista de elementos se encuentra en el mismo orden de donde se encuentran en el texto, donde la clave es '~' y el valor es un objeto Match simple que sólo contiene el string. Esto es así incluso si antes hay subreglas sueltas como .ws que hayan sido llamadas en primer lugar. Una llamada a .ast en tal objeto Match siempre devuelve un Str.
      • Saltará una advertencia si .caps o .chunks descubren que tienen correspondencias solapadas. En ausencia de estos solapamientos, .chunks garantiza el mapeo de cada parte de su string que haga match (entre .from y .to a exactamente un elemento de sus matches devueltos, obteniendo una cobertura completa.
      • [Conjetura: podemos tener también a .deepcaps y .deepchunks que expanden recursivamente cualquier captura que contenga submatches. Se supone que las claves de tales chunks devueltos podrían indicar el "pedigrí" de las correspondencias en el árbol de parseo].
    • Todos los intentos de match, finalizados con éxito o no, contra cualquier regex, subregla o subpatrón (ver más abajo) devuelven un objeto de clase Match. Esto es:
      • $match_obj = $str ~~ /patrón/; say "Matched" if $match_obj;
    • De forma automática, este objeto devuelto también está dentro de la léxica de la variable <$/> del entorno actual, independientemente de si tiene éxito. Esto es:
      • $str ~~ /patrón/; say "Hay Match" if $/;
    • Dentro de un regex, la variable contiene el objeto Match incompleto del regex, conocido como el estado del match (de tipo Cursor). Normalmente esto no se puede modificar a menos que sepas como crear y propagar estados de match. Todos los regex devuelven estados de match incluso cuando si piensas que están devolviendo otra cosa, porque los estados de match guardan la información de si se han encontrado los patrones o no por tí.
      • Afortunadamente, cuando quieras un resultado abstracto diferente con un objeto Match concreto y por defecto, puedes asociar tu valor devuelto con el estado actual del match utilizando la función make, que trabaja de forma parecida a return respetando el estado del match:
      • $str ~~ / foo # Hace match de 'foo' { make 'bar' } # Pero pretende que hagamos match de 'bar' /; say $(); # dice 'bar'
      • El objeto abstracto de cualquier objeto Match se hace mediante el método .ast.

Capturas de subpatrones

    • Cualquier parte de un regex entre paréntesis de captura es un subpatrón. Por ejemplo:
      • # subpatrón # _________________/\_____________________ # | | # | subpatrón subpatrón | # | ___/\___ __/\___ | # | | | | | | mm/ (Soy el (elefante), (gigante)**2 elegante) /;
    • Si el match tiene éxito, cada subpatrón del regex produce un objeto Match.
    • Cada objeto Match se añade al array que está dentro del objeto Match al que pertenece (conocido como su objeto Match padre). El alcance que pueda existir puede ser el del subpatrón más interno (si el subpatrón está anidado) o el regex completo en sí.
    • Al igual que todas las capturas, las asignaciones en el array son hipotéticas, y no se producirán si el subpatrón realiza un backtrack.
    • Por ejemplo, si el siguiente patrón hace match con éxito:
      • # subpat-A # _________________/\_____________________ # | | # | subpat-B subpat-C | # | ___/\___ __/\___ | # | | | | | | mm/ (Soy el (elefante), (gigante)**2 elegante) /;
      • los objetos Match representan los matches realizados por subpat-B y subpat-C que podrán ser añadidos con éxito dentro del array del objeto Match de subpat-A. El objeto Match de subpat-A puede añadirse a sí mismo en el array del objeto Match para el regex completo (dentro del array $/).
    • Como resultado de estas semáticas, los paréntesis de captura en Perl 6 son jerárquicos, no lineales (ver Capturas de subpatrones anidados).

Acceso a los subpatrones capturados

    • Los elementos del array de un objeto Match se referencian utilizando la notación estandar de acceso a arrays ($/[0], $/[1], $/[2], etc.) o mediante el correspondiente alias numérico del contexto léxico ($0, $1, $2, etc.). Por tanto:
      • say "$/[1] está entre $/[0] y $/[2]";
      • es lo mismo que:
      • say "$1 está entre $0 y $2";
    • Ten en cuenta que en Perl 6 las variables de captura numéricas comienzan en $0, no en $1, con los números correspondientes a los elementos de $/.
    • Los elementos del array del objeto Match del regex ($/) guardan los objetos Match de forma individual que representan a los substrings que hicieron match y fueron capturados en primer lugar, segundo, tercero, etc., (subpatrones externos no anidados). Por tanto estos elementos pueden ser tratados como los resultados más recientes del match. Por ejemplo:
      • if m/ (\d\d\d\d)-(\d\d)-(\d\d) (DC|AC)?/ { ($anio, $mes, $dia) = $/[0..2]; $era = "$3" if $3; # stringificado/booleanizado @pos_fecha = ( $0.from() .. $2.to() ); # Llamada a los métodos del Match }

Capturas de subpatrones anidados

    • Los substrings que hacen match mediante subpatrones anidados (capturas anidadas entre paréntesis) se asignan al array dentro del objeto Match del antecesor del subpatrón, no a $/ del array.
    • Este funcionamiento es totalmente distinto de las semánticas de Perl 5:
      • # Perl 5... # # $1-------------------------- $4--------- $5------------------------ # | $2-------------------- | | | | $6------ $7---------- | # | | $3-- | | | | | | | | | | # | | | | | | | | | | | | | | m/ ( Un (chico|chica|c(\S+) ) ) (mira|llama) ( (a la|al) (chica|chico) ) /x;
    • En Perl 6, los paréntesis anidados producen capturas anidadas:
      • # Perl 6... # # $0-------------------------- $1--------- $2------------------------ # | $0[0]---------------- | | | | $2[0]--- $2[1]------- | # | | $0[0][0] | | | | | | | | | | # | | | | | | | | | | | | | | m/ ( Un (chico|chica|c(\S+) ) ) (mira|llama) ( (a la|al) (chica|chico) ) /;

Cuantificación de las capturas de subpatrones

    • Si un subpatrón es cuantificado directamente (utilizando cualquier cuantificador), deja de producir un sólo objeto Match y produce una lista de objetos Match que se corresponden con la secuencia de los matches individuales realizados por el subpatrón repetido (o un Nil si hace match cero veces).
    • Debido a que un subpatrón cuantificado devuelve una lista de objetos Match, el elemento correspondiente del array para la captura cuantificada se guardará en un array (anidado) en vez de en un sólo objeto Match. Por ejemplo:
      • if m/ (\w+) \: (\w+ \s+)* / { say "Clave: $0"; # No cuantificado --> un sólo Match say "Valores: @($1)"; # Cuantificado --> array de Matches }

Cuantificación indirecta de las capturas de subpatrones

    • A veces un subpatrón puede anidarse dentro de una estructura cuantificada de no captura:
      • # no captura cuantificador # __________/\____________ __/\__ # | || | # | $0 $1 || | # | _^_ ___^___ || | # | | | | | || | m/ [ (\w+) \: (\w+ \h*)* \n ] ** 2..* /
      • Los corchetes de no captura no tienen un alcance léxico anidado y separado, por eso los dos subpatrones internos todavía están en el nivel más alto del regex y sus designaciones son: $0 y $1.
    • Sin embargo, debido a que los dos supatrones están dentro de una estructura cuantificada, $0 y $1 tendrán un array cada uno. Los elementos de tales arrays serán los submatches devueltos por los subpatrones correspondientes de cada iteración de los paréntesis de no captura. Por ejemplo:
      • my $texto = "foo:food fool\nbar:bard barb";
      • # $0-- $1------ # | | | | $texto ~~ m/ [ (\w+) \: (\w+ \h*)* \n ] ** 2..* /;
      • # Debido a que están en un bloque cuantificado de no captura... # $0 contiene el equivalente de: # # [ Match.new(str=>'foo'), Match.new(str=>'bar') ] # # y $1 contiene el equivalente de: # # [ Match.new(str=>'food '), # Match.new(str=>'fool' ), # Match.new(str=>'bard '), # Match.new(str=>'barb' ), # ]
    • Contrastando, si la estructura exterior cuantificada es una estructura de captura (un subpatrón), entonces tendrá un alcance léxico anidado. Esa estructura exterior cuantificada devolverá un array de objetos Match que representarán las capturas que están dentro de los paréntesis por cada iteración (ahora la describimos). Esto es:
      • my $texto = "foo:food fool\nbar:bard barb";
      • # $0----------------------- # | | # | $0[0] $0[1]--- | # | | | | | | $texto ~~ m/ ( (\w+) \: (\w+ \h*)* \n ) ** 2..* /;
      • # Debido a que es un bloque de captura cuantificada, # $0 contiene el equivalente de: # # [ Match.new( str=>"foo:food fool\n", # arr=>[ Match.new(str=>'foo'), # [ # Match.new(str=>'food '), # Match.new(str=>'fool'), # ] # ], # ), # Match.new( str=>'bar:bard barb', # arr=>[ Match.new(str=>'bar'), # [ # Match.new(str=>'bard '), # Match.new(str=>'barb'), # ] # ], # ), # ] # # y ahí no hay $1
    • En otras palabras, los paréntesis de no captura cuantificada tiene sus componentes en listas manejables y planas, mientras que los paréntesis de captura cuantificada tienen sus componentes es una estructura jerárquica manejable.

Numeración de subpatrones

    • El índice de un subpatrón dado siempre puede determinarse de forma estática, pero no es necesariamente la única forma ni tiene porque ser siempre igual. La numeración de subpatrones comienza en cada alcance léxico (en un regex, en un subpatrón o en una rama de una alternación).
    • De forma particular, el ínidce de los paréntesis de captura comienza después de cada | o || (pero no después de cada & o &&). De ahí:
      • # $0 $1 $2 $3 $4 $5 $conejitos = rx/ (saltan) (los) (conejos) (y se) (miran al), (espejo) # $0 $1 $2 $3 $4 | (dan) (la) (vuelta) (y se) (van) /;
      • Esto significa que si hace match la segunda alternación, el array @$/ contendrá ('dan', 'la', 'vuelta', 'y se', 'van') en vez de (undef, undef, undef, undef, undef, undef, 'dan', 'la', 'vuelta', 'y se', 'van') (como lo haría Perl 5 con el mismo regex).
    • Todavía es posible imitar la captura monótona de Perl 5 indexando semánticas. Más detalles en Alias de escalares numerados más abajo.

Capturas de subreglas

    • Cualquier llamada a un nombre de <regex> dentro de un patrón es conocida como una subregla, ya esté actualmente definida como un regex o un token o una regla o incluso un method ordinario o un multi.
    • Cualquier construcción acotada con un alias (ver Alias más abajo) a un nombre de variable también es una subregla.
    • Por ejemplo, este regex contiene tres subreglas:
      • # subregla subregla subregla # __^__ _______^_____ __^__ # | | | | | | m/ <ident> $<spaces>=(\s*) <digit>+ /
    • Igual que los subpatrones, cada match finalizado con éxito en un regex produce un objeto Match. Pero, a diferencia de los subpatrones, ese objeto Match no es asignado al array dentro de su objeto Match padre. En vez de eso, se le asigna a una entrada del hash dentro de su objeto Match padre. Por ejemplo:
      • # .... $/ ..................................... # : : # : .... $/[0] .................. : # : : : : # : $/<ident> : $/[0]<ident> : : # : __^__ : __^__ : : # : | | : | | : : mm/ <ident> \: ( antes conocido como <ident> ) /

Acceso a capturas de subreglas

    • Las entradas hash de un objeto Match se pueden referenciar utilizando cualquiera de las notaciones de acceso a hash estandar ($/{'foo'}, $/<bar>, $/«baz», etc.), o mediante los alias de alcance léxico correspondientes ($<foo>, $«bar», $<baz>, etc.). Por tanto, el ejemplo anterior también implica:
      • # $<ident> $0<ident> # __^__ __^__ # | | | | mm/ <ident> \: ( antes conocido como <ident> ) /
    • No hay diferencia si las reglas utilizan mayor/menor que (<ident>) o alias internos (<ident=nombre>) o alias externos ($<ident>=(<alpha>\w*)). La cosa es el nombre.

Capturas repetidas de la misma subregla

    • Si una subregla aparece dos (o más) veces en cualquier rama de un alcance léxico (dos veces dentro del mismo subpatrón y alternación), o si la subregla se cuantifica en cualquier sitio dentro del alcance dado, su entrada de hash correspondiente siempre se asigna a un array de objetos Match en vez de a un sólo objeto Match.
    • Los matches sucesivos de la misma subregla (ya sean de llamadas separadas o de una sola repetición cuantificada) añaden a este array sus objetos Match de forma individual. Por ejemplo:
      • if mm/ mv <file> <file> / { $from = $<file>[0]; $to = $<file>[1]; }
      • (Por claridad aquí hemos ignorado las sutilezas de los espacios en blanco-- las reglas sigspace normales pueden requerir espacios sólo entre caracteres alfanuméricos, lo cual es incorrecto. Asumimos que nuestra subregla del fichero se hace cargo de los espacios en blanco por su cuenta).
      • Igualmente, con una subregla cuantificada:
      • if mm/ mv <file> ** 2 / { $from = $<file>[0]; $to = $<file>[1]; }
      • Y con una mezcla de ambas:
      • if mm/ mv <file>+ <file> / { $to = pop @($<file>); @from = @($<file>); }
    • Sin embargo, si una subregla se renombra de forma explícita (o a su alias -- ver Alias), sólo el nombre nuevo cuenta para decidir si se repite o no. Por ejemplo:
      • if mm/ mv <file> <dir=file> / { $from = $<file>; # Sólo un nombre de subregla <file>, por tanto es escalar $to = $<dir>; # La captura es conocida formalmente como <file> }
      • Igualmente, ninguna de las siguientes construcciones hacen que <file> produzca un array de objetos Match debido a que ninguna de ellas tienen dos o más subreglas <file> en el mismo alcance léxico:
      • if mm/ (keep) <file> | (toss) <file> / { # Cada <file> está en una alternación por separado, por tanto <file> # no se repite en ningún alcance, por tanto $<file> # no es un objeto Array... $action = $0; $target = $<file>; }
      • if mm/ <file> \: (<file>|none) / { # El segundo <file> está anidado en un subpatrón que da # un alcance distinto... $actual = $/<file>; $virtual = $/[0]<file> if $/[0]<file>; }
    • Por otro lado, los corchetes que no son alias no ofrecen un alcance por separado (porque no tienen un objeto Match asociado). Por tanto:
      • if mm/ <file> \: [<file>|none] / { # Dos <file>s en el mismo alcance $actual = $/<file>[0]; $virtual = $/<file>[1] if $/<file>[1]; }

Alias

Los alias pueden ser nombrados o numerados. Pueden ser de tipo escalar, array o hash, y se pueden aplicar tanto a constructores de captura o no captura. Las secciones siguientes destacan las características especiales de las semánticas de algunas de estas combinaciones.

Alias escalar numerado con subpatrones

    • Si un alias escalar numerado se aplica a un conjunto de paréntesis de captura:
      • # ___/paréntesis de captura\__ # | | # | | mm/ $<key>=( (<[A..E]>) (\d**3..6) (X?) ) /;
      • los paréntesis de captura exteriores no hacen la captura en el array $/ como lo podría hacer unos paréntesis sin alias. En cambio, estos paréntesis capturan dentro del hash de $/; concretamente dentro del elemento del hash donde la clave es el nombre del alias.
    • Por tanto, en el ejemplo anterior, un match finalizado con éxito establece $<key> (por ej. $/<key>), pero no $0 (por ej. no $/[0]).
    • Más concreto:
        • $/<key> contendrá el objeto Match que podría haber estado antes en $/[0].
        • $/<key>[0] contendrá las letras A-E,
        • $/<key>[1] contendrá los dígitos,
        • $/<key>[2] contendrá la X opcional.
    • Otra forma de ver este funcionamiento es que los paréntesis del alias crean una clase de alcance léxico llamada subregla, donde los contenidos de los paréntesis se tratan como si fueran parte de una subregla separada cuyo nombre es el alias.

Alias escalar con nombre, en corchetes de no captura

    • Si se aplica un alias escalar con nombre a un conjunto de corchetes de no captura:
      • # _/corchetes de no captura\__ # | | # | | mm/ $<key>=[ (<[A..E]>) (\d**3..6) (X?) ] /;
      • el correspondiente objeto Match de $/<key> contendrá sólo el string que ha realizado match por los corchetes de no captura.
    • Concretamente, el array de la entrada $/<key> está vacío. Esto es porque los corchetes no crean un alcance léxico anidado, por tanto los subpatrones no se anidan y se corresponden con $0, $1 y $2, y no con $/<key>[0], $/<key>[1] y $/<key>[2].
    • Con otras palabras:
        • $/<key> contendrá el substring completo que ha realizado match por los corchetes (en un objeto Match, como describimos antes),
        • $0 contendrá las letras A-E,
        • $1 contendrá los dígitos,
        • $2 contendrá la X opcional.

Alias escalar con nombre en subreglas

    • Si una subregla tiene un alias, ésta asigna su objeto Match a la entrada del hash cuya clave es el nombre del alias, y no asignará cualquier cosa más a la entrada del hash cuya clave sea el nombre de la subregla. Esto es:
      • if m/ ID\: <id=ident> / { say "Identificado como $/<id>"; # $/<ident> no está definido }
    • Por tanto, hacer un alias de una subregla cambia el destino del objeto Match de la subregla. Esto es útil para diferenciar dos o más llamadas a la misma subregla en el mismo alcance. Por ejemplo:
      • if mm/ mv <file>+ <dir=file> / { @from = @($<file>); $to = $<dir>; }

Alias de escalares numerados

    • Si se utiliza un alias numerado en vez de un alias con nombre:
      • m/ $1=(<-[:]>*) \: $0=<ident> /
      • el funcionamiento es el mismo que para los alias con nombre (como los casos descritos antes), excepto que el objeto Match resultante se asigna al elemento correspondiente del array apropiado en vez de a un elemento del hash.
    • Si se utiliza cualquier alias numerado, la numeración de los subpatrones siguientes sin alias en el mismo alcance es incrementado automáticamente desde ese número del alias (es mucho más parecido al incremento de valores desde el último valor explícito). Esto es:
      • # ---$1---- -$2- --$6--- -$7- # | | | | | | | | m/ $1=(comida) (palo) $6=(bazd) (quxd) /;
    • Este mecanismo de seguimiento es útil para reimplantar las semánticas de Perl 5 para la numeración de subpatrones consecutivos en alternaciones:
      • $conejitos = rx/ (saltan) (los) (conejos) (y se) (miran al), (espejo) | $6 = (dan) (la) (vuelta) (y se) (van) # $7 $8 $9 $10 /;
    • También ofrece una forma sencilla en Perl 6 para reimplantar las semánticas numeradas no anidadas de los subpatrones anidados de Perl 5:
      • # Perl 5... # $1 # _____________/\___________ # | $2 $3 $4 | # | __/\___ __/\___ /\ | # | | | | | | | | m/ ( ( [A-E] ) (\d{3,6}) (X?) ) /x;
      • # Perl 6... # $0 # ______________/\______________ # | $0[0] $0[1] $0[2] | # | ___/\___ ____/\____ /\ | # | | | | | | | | m/ ( (<[A..E]>) (\d ** 3..6) (X?) ) /;
      • # Perl 6 simulando Perl 5... # $1 # _______________/\________________ # | $2 $3 $4 | # | ___/\___ ____/\____ /\ | # | | | | | | | | m/ $1=[ (<[A..E]>) (\d ** 3..6) (X?) ] /;
      • Los corchetes de no captura no crean un alcance, por eso los subpatrones que están dentro de ellos tienen el alcance del regex y se numeran desde el nivel más alto. Hacer un alias de los corchetes a $1 quiere decir que el siguiente subpatrón del mismo nivel (por ej. (<[A..E]>)) se numera secuencialmente (por ej. $2, etc.

Alias escalares aplicados a constructores cuantificados

    • Todas las semánticas vistas se aplican por igual a los alias de las estructuras cuantificables.
    • La única diferencia es que, si el alias del constructor es una subregla o un subpatrón, tal subregla cuantificable o subpatrón devolverá una lista de objetos Match (como los descritos en Cuantificación de las capturas de subpatrones y Capturas repetidas de la misma subregla). Por tanto, el elemento del array correspondiente o la entrada hash del alias contendrá un array en lugar de un sólo objeto Match.
    • En otras palabras, los alias y la cuantificación son completamente ortogonales. Por ejemplo:
      • if mm/ mv $0=<file>+ / { # <file>+ devuelve una lista de objetos Match, # por tanto $0 contiene un array de objetos Match, # uno por cada llamada con éxito a <file>
      • # $/<file> no existe (antes es vaciado por el alias) }
      • if m/ mv \s+ $<from>=(\S+ \s+)* / { # Los subpatrones cuantificados devuelven una lista de objetos Match, # por tanto $/<from> conntiene un array de objetos Match # uno por cada match del subpatrón realizado con éxito
      • # $0 no existe (antes es vaciado por el alias) }
    • Sin embargo, un conjunto de corchetes de no captura cuantificada siempre devuelve un sólo objeto Match que contiene sólo el substring completo que hizo match por el conjunto completo de repeticiones de los corchetes (ya descritos en Alias escalar con nombre, en corchetes de no captura). Por ejemplo:
      • "coffee fifo fumble" ~~ m/ $<effs>=[f <-[f]> ** 1..2 \s*]+ /;
      • say $<effs>; # visualiza "fee fifo fum"

Alias de array

    • Un alias también puede ser especificado utilizando un array como un alias en lugar de un escalar. Por ejemplo:
      • m/ mv \s+ @<from>=[(\S+) \s+]* <dir> /;
    • Utilizar la notación @alias= en lugar de $alias hace que la entrada hash o el elemento del array correspondiente siempre reciba un array de objetos Match, incluso si el constructor que hará de alias pudiera devolver normalmente un sólo objeto Match. Esto es útil para crear semánticas de captura consistentes entre alternaciones estructuradas distintas (para forzar las capturas de array en todas las ramas):
      • mm/ Sr?a? @<nombres>=<ident> W\. @<nombres>=<ident> | Sr?a? @<nombres>=<ident> /;
      • # Alias a @nombres quiere decir que $/<nombres> siempre es # un objeto array, por tanto...
      • say @($/<nombres>);
    • Por consistencia y conveniencia, @<key> también puede utilizarse fuera de un regex, como una abreviación de @( $/<key> ). Esto es:
      • mm/ Sr?a? @<nombres>=<ident> W\. @<nombres>=<ident> | Sr?a? @<nombres>=<ident> /;
      • say @<nombres>;
    • Si un alias de array se aplica a un par de corchetes cuantificados de no captura, éstos capturan los matches de los substrings de cada repetición de los corchetes en elementos separados en el array correspondiente. Esto es:
      • mm/ mv $<files>=[ f.. \s* ]* /; # $/<files> se asigna a un sólo # objeto Match que contiene el # match del substring completo # de todo el conjunto de repeticiones # de los corchetes de no captura
      • mm/ mv @<files>=[ f.. \s* ]* /; # $/<files> se asigna a un array, # donde cada elemento es un objeto # Match que contiene el match del # substring de la enésima repetición # del match de los corchetes de no # captura
    • Si un alias de array se aplica a un par de paréntesis cuantificados de captura (un subpatrón), se asigna el hash o elemento del array correspondiente a una lista mediante la concatenación de los valores del array con cada objeto Match devuelto por una repetición del subpatrón. Esto es, un alias de un array en un subpatrón recopila y pone al mismo nivel todas las capturas anidadas de subpatrones que están dentro del alias del subpatrón. Por ejemplo:
      • if mm/ $<pares>=( (\w+) \: (\N+) )+ / { # Alias escalar, por tanto $/<pares> se asigna a un array # de objetos Match, donde cada uno tiene su propio array # de dos subcapturas...
      • for @($<pares>) -> $par { say "Clave: $par[0]"; say "Valor: $par[1]"; } }
      • if mm/ @<pares>=( (\w+) \: (\N+) )+ / { # Alias de array, por tanto $/<pares> se asigna a un array # de objetos Match, donde cada uno están al mismo nivel fuera de # las dos subcapturas que hay dentro del subpatrón
      • for @($<pares>) -> $key, $val { say "Clave: $key"; say "Valor: $val"; } }
    • Igualmente, si un alias de array se aplica a una subregla cuantificada, el correspondiente elemento de array o hash del alias se asigna a una lista con los valores del array por cada objeto Match devuelto por cada repetición de la subregla, todos al mismo nivel dentro de un sólo array:
      • rule par { (\w+) \: (\N+) \n }
      • if mm/ $<pares>=<par>+ / { # Alias escalar, por tanto $/<pares> contiene un array de # objetos Match, donde cada uno es el resultado de la # llamada a la subregla <par>...
      • for @($<pares>) -> $par { say "Clave: $par[0]"; say "Valor: $par[1]"; } }
      • if mm/ mv @<pares>=<par>+ / { # Alias de array, por tanto $/<pares> contiene un array de # objetos Match (todos al mismo nivel) desde los arrays # anidados de los objetos Match devueltos por cada match # de la subregla <par>...
      • for @($<pares>) -> $key, $val { say "Clave: $key"; say "Valor: $val"; } }
    • Dicho de otro modo, un alias de array es útil para meter en un sólo array cualquier captura anidada que pudiera ocurrir dentro de un subpatrón o subregla cuantificados. Mientras, un alias escalar es útil para conservar en un array de primer nivel la estructura interna de cada repetición.
    • También es posible utilizar una variable numerada como alias de array. Las semánticas son las mismas que las descritas antes, con la única diferencia que el array resultante de los objetos Match se asignan dentro del elemento apropiado del array de matches del regex en lugar de en una clave en el hash de su match. Por ejemplo:
      • if m/ mv \s+ @0=((\w+) \s+)+ $1=((\W+) (\s*))* / { # | | # | | # | \_ Alias escalar, $1 genera un # | array, donde cada elemento es # | un objeto Match que contiene # | las dos capturas anidadas # | # \___ Alias de array, $0 genera un array de un nivel con # las capturas (\w+) de cada repetición
      • @from = @($0); # Lista de un nivel
      • $to_str = $1[0][0]; # Elementos anidados de $to_gap = $1[0][1]; # una lista de varios niveles }
    • Ten en cuenta de nuevo, que fuera de un regex, @0 es sólo una abreviación de @($0), por tanto la primera asignación de antes también podría ser:
      • @from = @0;

Alias de hash

    • También se puede especificar un alias utilizando un hash como el alias de la variable en lugar de un escalar o un array. Por ejemplo:
      • m/ mv %<ubicacion>=( (<ident>) \: (\N+) )+ /;
    • Un alias de hash produce el hash o elemento de array correspondiente en el alcance actual del objeto Match para asignarse a un objeto (anidado) Hash (en lugar de un objeto Array o un sólo objeto Match).
    • Si se aplica el alias de hash a una subregla o subpatrón, la primera captura numérica anidada se convierte en la clave de cada entrada del hash y cualquier otra captura numérica restante se convierte en los valores (en un array si hay más de una).
    • Como con los alias de array, también es posible usar variables numeradas como alias de hash. De nuevo, la única diferencia es dónde se guarda el objeto Match resultante:
      • rule uno_a_muchos { (\w+) \: (\S+) (\S+) (\S+) }
      • if mm/ %0=<uno_a_muchos>+ / { # $/[0] contiene un hash, donde cada clave es # la primera subcaptura dentro de C<uno_a_muchos>, y cada # valor es un array que contiene las subcapturas de la # segunda, tercera, cuarta, etc. subregla...
      • for %($/[0]) -> $par { say "Uno: $par.key()"; say "Muchos: { @($par.value) }"; } }
    • Fuera del regex, %0 es un cortocircuito de %($0):
      • for %0 -> $par { say "Uno: $par.key()"; say "Muchos: @($par.value)"; }

Alias externos

    • En lugar de utilizar alias internos como:
      • m/ mv @<files>=<ident>+ $<dir>=<ident> /
      • puede utilizarse el nombre de una variable ordinaria como un alias externo, como:
      • m/ mv @OUTER::files=<ident>+ $OUTER::dir=<ident> /
    • En este caso, el comportamiento de cada alias es igual al descrito en las secciones anteriores, excepto que cualquier captura resultante está directamente (todavía de forma hipotética) dentro de la variable del nombre especificado que debe existir todavía en el alcance de la declaración del regex.

Captura de matches repetidos

    • Cuando hace match con éxito un regex completo con repeticiones (especificado mediante la bandera :x o :g o se solapa (especificado mediante la bandera :ov o :ex), normalmente producirá una serie de matches distintos.
    • Un match con éxito bajo cualquiera de esas banderas todavía devuelve un solo objeto Match en $/. Sin embargo, este objeto puede representar una evaluación incompleta del regex. Es más, los valores de este objeto match son un poco distintos de las que da un match sin repeticiones:
        • Dependiendo de donde haga match el patrón, el valor booleano de $/ después de estos matches puede ser verdad o falso.
        • El valor del string es el substring desde el comienzo del primer match hasta el final del último match (incluyendo cualquier parte del string que el regex no haya tenido en cuenta para encontrar matches anteriores).
        • Las subcapturas se devuelven como una lista multidimensional, donde el usuario puede elegir entre dos formas de procesado. Si haces referencia a @(), se ignora la multidimensionalidad y todos los matches se devuelven en un nivel (todavía de forma perezosa). Si haces referencia a @@(), puedes tener cada sublista de forma individual como un objeto Capture. (Esto es, hay un operador de coacción en @@(), como @(), por defecto a $/. Como con cualquier lista multidimensional, cada sublista puede separarse de forma perezosa.
      • Por ejemplo:
      • if $texto ~~ mm:g/ (\S+:) <roca> / { say "El contexto del match completo es: [$/]"; }
      • También está disponible la lista de objetos match de forma individual que corresponde a cada match por separado:
      • if $texto ~~ mm:g/ (\S+:) <rocks> / { say "Ha hecho match { +@@() } veces"; # Nota: aquí fuerza el más próximo
      • for @@() -> $m { say "Ha hecho match entre $m.from() y $m.to()"; say '¡Derecho, tío!' if $m[0] eq 'Perl'; say "Duro como una $m<roca>"; } }

:keepall

    • Todos los regexes recuerdan todo si se utiliza :keepall en cualquier lugar del alcance dinámico externo. En este caso, todo lo que hay dentro de los símbolos mayor/menor es parte de la clave. Supón este ejemplo utilizando espacios en blanco:
      • / <key> <.ws> '=>' <.ws> <value> { %hash{$key} = $value } /
      • Las dos instancias de <.ws> guardarían un array de dos valores accesible como @<.ws>. También podría guardar el match literal dentro de $<'=\>'>. Para asegurarse de que no se olvida nada, bajo :keepall se adjunta cualquier texto o espacio en blanco como propiedad añadida del nodo en cuestión. (El nombre de esta propiedad es "pretext").

Gramáticas

    • Tu regla privada ident no suele respetar a cualquier cosa que no sea a sí misma. Por tanto, se necesita algún mecanismo para meter a las reglas en un espacio de nombres.
    • Si las subs son el modelo de las reglas, los módulos/clases son el modelo obvio para añadirlas. Estas colecciones de reglas normalmente se conocen como gramáticas.
    • Una clase puede tener nombres de acciones juntas:
      • class Identidad { method nombre { "Nombre = $.nombre" } method edad { "Edad = $.edad" } method direcc { "Direcc = $.direcc" }
      • method desc { print &.nombre(), "\n", &.edad(), "\n", &.direcc(), "\n"; }
      • # etc. }
      • Por tanto, una gramática también puede tener un conjunto de nombres de reglas juntos:
      • grammar Identidad { rule nombre { Nombre '=' (\N+) } rule edad { Edad '=' (\d+) } rule direcc { Direcc '=' (\N+) } rule desc { <nombre> \n <edad> \n <direcc> \n }
      • # etc. }
    • Como las clases, las gramáticas pueden heredar:
      • grammar Carta { rule texto { <saludo> <cuerpo> <despedida> }
      • rule saludo { [Hey|Hola] $<to>=(\S+?) , $$}
      • rule cuerpo { <line>+? } # nota: se hace backtrack hacia adelante via +?
      • rule despedida { Chao, $<from>=(.+) }
      • # etc. }
      • grammar CartaFormal is Carta {
      • rule saludo { Estimado/a $<to>=(\S+?) , $$}
      • rule despedida { Le saluda atentamente, $<from>=(.+) }
      • }
    • Al igual que los métodos de una clase, las definiciones de la regla de una gramática se heredan (¡y son polimórficas!). No es necesario especificar de nuevo line, etc.
    • Perl 6 viene al menos con una gramática predefinida:
      • grammar STD { # La gramática estandar propia de Perl
      • rule prog { <declaracion>* }
      • rule declaracion { | <decl> | <loop> | <label> [<cond>|<sideff>|;] }
      • rule decl { <sub> | <class> | <use> }
      • # etc. etc. etc. }
    • Igualmente:
      • given $codigo_fuente { $arbol_parseo = m:keepall/<Perl::prog>/; }
    • Para cambiar a una gramática distinta en el medio de una regex, tienes que usar el advervio :lang. Por ej., para hacer match de la expresión <expr> desde $funnylang (entre llaves), hay que poner:
      • token funnylang { '{' [ :lang($funnylang.unbalanced('}')) <expr> ] '}' }
    • Un string puede hacer match contra una gramática llamando a .parse en la gramática, y pasa opcionalmente un objeto action a la gramática:
      • MiGramatica.parse($str, :action($action-object))
      • Si una acotación dentro de una gramática devuelve un objeto Whatever, el motor gramatical intenta llamar a un método del mismo nombre que el nombre del regex actual en el objeto acción, pasando como primer argumento posicional el objeto Match actual, y como segundo argumento posicional (si lo hay) la etiqueta de reducción. La etiqueta se da mediante el comentario #= como {*} después en la misma línea . Debe existir un espacio entre #= y la etiqueta, y la etiqueta en sí puede contener espacios.
      • grammar Entero { token ARRIBA { | 0b<[01]>+ {*} #= binario | \d+ {*} #= decimal } } class Dos { multi method ARRIBA($match, $tag) { my $texto = ~$match; $texto = :2($texto) if $tag eq 'binario' make $texto; } multi method ARRIBA($match) { make 2 * $match.ast; } } Entero.parse('21', :action(Dos.new)).ast # 42
      • El método es llamado sin el argumento tag, y al final de cada regla se asume un {*}. El {*} implícito está fuera de la alternación en la regla ARRIBA de antes, independientemente de que no se utilicen corchetes de forma explícita.

Categorías sintácticas

Para que puedas escribir tus propias subreglas para aserciones y backslash, puedes ampliar (tu copia del) sublenguaje Regex utilizando las siguientes categorías sintácticas:

augment argot Regex { token backslash:sym<y> { ... } # define tus propias \y y \Y token assertion:sym<*> { ... } # define tu propio <*loquesea> token metachar:sym<,> { ... } # define un nuevo metacaractera

multi method tweak (:$x) {...} # define tu propio modificador :x }

Pragmas

Pueden utilizarse varios pragmas para controlar usos y aspectos varios de la compilación del regex que de otra manera no se podrían hacer. Éstos están ligados a la declaración en cuestión:

use s :foo; # controla a s por defecto use m :foo; # controla a m por defecto use rx :foo; # controla a rx por defecto use regex :foo; # controla a regex por defecto use token :foo; # controla a token por defecto use rule :foo; # controla a rule por defecto

(Es una política general en Perl 6 que cualquier pragma diseñado para influenciar ligeramente el funcionamiento de una palabra clave es idéntico a la palabra clave en sí, a menos que exista una buena razón para que no sea así. Por otro lado, los pragmas que están diseñados para influenciar semánticas profundas no deberían llamarse igual, aunque, claro está, alguna similitud no estaría mal.)

Transliteración

    • El operador acotado como tr/// ahora también tiene un método llamado trans(). Su argumento es una lista de pares. Puedes utilizar cualquier cosa que genere una lista de pares:
      • $str.trans( %mapeo.pares.ordenado );
      • Utiliza la forma .= para realizar la transliteración:
      • $str.=trans( %mapeo.pares.ordenado );
      • (Perl 6 no soporta la forma y///, que se utiliza sólo con sed porque no soporta letras por separado).
    • Las dos partes de un par pueden ser strings interpretados como tr///:
      • $str.=trans( 'A..C' => 'a..c', 'XYZ' => 'xyz' );
      • Como un caso degenerado, cada parte puede tener un sólo caracter:
      • $str.=trans( 'A'=>'a', 'B'=>'b', 'C'=>'c' );
      • Los caracteres de espacios en blanco pueden tomarse literalmente como caracteres para realizar desde o hacia la transliteración. Sólo es reconocida la metasintaxis de la secuencia de rango .. dentro de un string, aunque también puedes utilizar las interpolaciones con backslash entre comillas dobles. Si la parte derecha es demasiado corta, se replica el caracter final hasta la longitud del string de la izquierda. Si aquí no hay caracter final porque la parte derecha es el string null, el resultado es un borrado.
    • Ambas partes del par también pueden ser objetos Array:
      • $str.=trans( ['A'..'C'] => ['a'..'c'], <X Y Z> => <x y z> );
      • La versión array es como la forma primitiva: la semántica de la forma del string equivale exactamente a la primera expansión de .., y entonces el string se divide en caracteres individuales como elementos del array.
    • La versión array puede mapear uno o más caracteres a uno o más caracteres:
      • $str.=trans( [' ', '<', '>', '&' ] => ['&nbsp;', '&lt;', '&gt;', '&amp;' ]);
      • En el caso de que hagan match más de una secuencia de entrada de caracteres, gana el más largo. En el caso de dos secuencias idénticas, gana el primero del orden.
      • Al igual que la forma string, los elementos que falten de la derecha se replican del elemento final, y se produce una eliminación si hay un array null.
    • El reconocimiento realizado por las formas string y array es muy básica. Para conseguir más fortaleza, cualquier elemento de reconocimiento de la parte izquierda puede ser especificado por un regex que pueda realizar clases de caracter, lookahead, etc.
      • $str.=trans( [/ \h /, '<', '>', '&' ] => ['&nbsp;', '&lt;', '&gt;', '&amp;' ]);
      • $str.=trans( / \s+ / => ' ' ); # deja todos los espacios en blanco en un espacio $str.=trans( / <!alpha> / => '' ); # elimina todo lo que no sea alfanumérico
      • Estos submatches se mezclan dentro del match de la misma forma que se mezclan dentro de una alternación paralela en el procesamiento ordinario del regex, por tanto, las reglas de token largo se aplican a todos los matches posibles especificados por el operador de transliteración. Una vez realizados el match y la transliteralización, el matching vuelve a la nueva posición que sigue al final del match anterior, incluso si se produce el match en varios caracteres.
    • Si la parte derecha de la flecha es un cierre, se evalúa para determinar el valor de sustitución. Si la parte izquierda hizo match por un regex, el objeto match resultante estará disponible dentro del cierre.

Sustitución

También hay formas para los métodos m// y s///:

$str.match(/pat/); $str.subst(/pat/, "sustituto"); $str.subst(/pat/, {"sustituto"}); $str.=subst(/pat/, "sustituto"); $str.=subst(/pat/, {"sustituto"});

Aquí no hay una sintaxis dulce, por tanto, para conseguir una evaluación diferida de la sustitución tienes que acotarla. La sintaxis dulce las dan sólo las formas con barras. Esta es la forma estandar de "tres barras":

s/patrón/sustituto/

En las "tres barras" sólo pueden utilizarse caracteres sin paréntesis y buena cerveza. La parte derecha siempre se evalúa como si fuera un string entre comillas dobles independientemente de la acotación elegida.

Al igual que en Perl 5, también se soporta una forma entre corchetes, pero a diferencia de Perl 5, Perl 6 utiliza los corchetes sólo para el patrón. La sustitución se especifica como si fuera una asignación de elemento ordinaria, con las reglas de acotación ordinarias. Para poner tu propia acotación en la derecha utiliza una de las formas q. La sustitución de antes equivale a:

s[patrón] = "sustituto"

o

s[patrón] = qq[sustituto]

Esta no es una forma normal de asignación porque la parte derecha se evalúa cada vez que hace match el sustituto (más parecido a la pseudoasignación de declaraciones que raras veces ocurre). Por consiguiente, esto se trata como un "thunk", esto es, como si estuviera implícitamente dentro de unas llaves. De hecho, no tiene mucho sentido decir

s[patrón] = { hazlo }

porque esto intentaría sustituir un cierre dentro de un string.

Se puede utilizar cualquier operador de asignación escalar; la macro de sustitución sabe cómo hacer el cambio

$destino ~~ s:g[patrón] op= expr

dentro de algo parecido a:

$destino.subst(rx:g[patrón], { $() op expr })

Por ejemplo, puedes multiplicar cada cantidad de dólares por 2 con:

s:g[\$ <( \d+ )>] *= 2

(El optimizador es libre de hacerlo más rápido que la llamada actual al método).

Fíjate en el último ejemplo que las sustituciones sólo ocurren en el string "oficial" resultante del match, esto es, la parte del string entre las posiciones $/.from y $/.to. (Lo hemos puesto de forma explícita con el par <(...)>; sino tendríamos que haber utilizado un lookbehind para hacer match de $).

Posicionamiento del match, tipos de ancho fijo

    • Normalmente para ir a una posición en particular puedes utilizar la aserción <at($pos)>, y con esto quedaría como posición actual la posición del objeto dado. Puedes establecer la posición actual del match mediante los modificadores :c y :p.
      • No obstante, recuerda por favor, que en Perl 6 las posiciones de los strings normalmente no son enteros, son objetos que apuntan a un lugar en particular del string independientemente de si utilizas bytes, puntos de código o grafemas. Si utilizas enteros, la aserción at asumirá que el alcance léxico actual será a nivel Unicode, y se supone que el entero se generó en este mismo alcance léxico. Se producirá una excepción si esto ocurre fuera de los niveles de abstracción Unicode permitidos del string actual. Consultar S02 para obtener más información acerca de las posiciones string.
    • Los tipos Buf se basan en células de ancho fijo y por tanto pueden manejar posiciones de enteros bastante bien y tratarlos como índices de array. En concreto, buf8 (también conocido como buf) es un string de un byte de la vieja escuela. Sólo pueden hacer match con tipos Buf las semánticas ASCII en ausencia de un modificador explicit que pregunte por los valores del array para tratarlos en alguna codificación concreta como UTF-32. (Esto también se cumple para los arrays compactos que se consideran isomórficos a los tipos Buf). Las posiciones dentro de los tipos Buf siempre son enteros, y se cuenta uno por cada célula del array. Ten cuidado porque las posiciones "from" y "to" son tratadas como si estuvieran entre elementos. Si se produce el match contra un array compacto @foo, la posición final 42 indica que @foo[42] es el primer elemento no incluido.

Matching contra todo menos strings

    • Todo lo que pueda relacionarse con un string puede hacer match contra un regex. Esta característica es particularmente útil con streams de entrada:
      • my $stream := cat $fh.lines; # vincula un escalar con un filehandle
      • # y después...
      • $stream ~~ m/patrón/; # hace el match desde el stream
    • Cualquier array no compacto de strings con elementos mezclados u objetos puede hacer match contra un regex si lo presentas como un objeto con la interface Str, la cual no descarta que el objeto tenga otras interfaces como Array. Normalmente utilizarás cat para generarlo como un objeto:
      • @array.cat ~~ / foo <,> bar <elem>* /;
      • La subregla especial <,> hace match entre elementos. La aserción <elem> hace match de cualquier elemento de array individual. Equivale al metacaracter "punto" para el elemento entero.
      • Si los elementos del array son strings, se concatenan virtualmente dentro de un sólo string lógico. Si los elementos del array son tokens u objetos parecidos, los objetos deben ofrecer métodos apropiados para que las subreglas hagan match contra ellos. Hacer match de una aserción string contra un objeto que no ofrezca una vista de string producirá un fallo en la aserción. Sin embargo, las listas de objetos puros pueden parsearse por todo el match (incluyendo cualquier subregla) aunque éste sólo busque aserciones como:
      • <.esun(Perro)> <.emite(Ladrido)> <.puede('morder')>
      • Es admisible la mezcla de objetos y los strings en un array siempre y cuando estén en distintos elementos. Sin embargo, no puede incrustar objetos en strings. Por supuesto que, cualquier objeto puede pretender ser un elemento string si quiere, y por eso el objeto Cat puede utilizarse como un substring con las mismas restricciones que en el string principal.
      • Ten en cuenta que las advertencias de .from y .to devuelven objetos opacos dobles en matches contra un array, donde una posición en particular refleja una posición dentro del array y una posición (potencialmente) dentro de un string del array. No esperes hacer match con estos valores, ni tampoco esperes poder extraer un substring de cualquier elemento. [Conjetura: ¿O sí podrías?]
    • Para hacer match contra cada elemento de un array, utiliza el operador »:
      • @array».match($regex);
    • Para hacer match contra cualquier elemento de un array es suficiente con utilizar un matching inteligente ordinario:
      • @array ~~ $regex;

Cuando $/ es válido

Para ofrecer una implementación libre, la variable $/ no garantiza su definición hasta que se requiera que el patrón llegue a un punto de la secuencia (como completar el match, o llamar a un cierre incrustado, o incluso evaluar un submatch que requiera como argumento una expresión de Perl). Dentro del código regex, $/ oficialmente no está definido y hace referencia a $0 u otras variables de captura compiladas que saquen el valor actual sin hacer referencia a $/. Igualmente, una referencia a $<foo> necesariamente no significa $/<foo> dentro del propio regex. Durante la ejecución de un match, su estado actual se guarda en la variable $_ con el alcance léxico de la parte apropiada del match, pero no se garantiza que sea igual que con el objeto $/, porque $/ es de tipo Match, mientras que el estado del match es de tipo Cursor. (Esto depende realmente de la implementación del motor que hace match en los patrones).

En cualquier caso, en matches simples, todo esto es transparente al usuario, y fuera del código del regex (y dentro de las acotaciones dentro del regex) se garantiza que la variable $/ represente el estado del match en ese punto. Esto es, el código Perl normal siempre puede depender de que $<foo> signifique $/<foo>, y de que $0 signifique $/[0], aunque el código esté incrustado en una acotación dentro del regex o fuera del regex después de que finalice el match.