2012-08-11 7 views
12

He estado estudiando más de perldoc perlre, así como el Regular Expressions Cookbook y preguntas relacionadas en Stack Overflow y parece que no puedo encontrar lo que parece ser una expresión muy útil: ¿cómo sé el número de coincidencia actual?¿Hay alguna forma de evaluar el número de veces que una expresión regular de Perl ha coincidido?

hay expresiones para el último partido de grupo cerrado ($^N), contenido de fósforo 3 (\g{3} si entienden los docs correctamente), $', $& y $`. Pero no parece haber una variable que pueda usar que simplemente me diga cuál es el número de la coincidencia actual.

¿Realmente le falta? Si es así, ¿hay alguna razón técnica explicada por qué es difícil de implementar, o simplemente no estoy leyendo el perldoc con suficiente cuidado?

Tenga en cuenta que estoy interesado en una variable incorporada, NOT soluciones alternativas como usar (${$count++}).

Por contexto, intento construir una expresión regular que coincida solo con algunas instancias de una coincidencia (por ejemplo, coincida todas las apariciones del carácter "E" pero NO coincida con las ocurrencias 3, 7 y 10 donde 3, 7 y 10 son simplemente números en una matriz). Me encontré con esto al tratar de construir una respuesta más idiomática a this SO question.

Quiero evitar la evaluación de expresiones regulares como cadenas para insertar 3, 7 y 10 en la propia expresión regular.

+0

Tenga en cuenta que necesito el # de coincidencias, no el # de grupos capturados. – DVK

+0

'Tenga en cuenta que estoy interesado en una variable incorporada': si no está en perlvar perlvar, ¿existe? Supuse que Perlvar contiene * todas las variables incorporadas de Perl. – TLP

+1

No hay tal variable. perlvar no documenta todas las variables incorporadas, por ejemplo '@ ISA' no aparece, pero todo está documentado en alguna parte. Perl tiende a no tener funcionalidad oculta. ¿Puedes dar un ejemplo del problema que estás tratando de resolver que es mejor que la referencia que das? – Borodin

Respuesta

5

He jugado con esto un poco. De nuevo, sé que esto no es realmente lo que estás buscando, pero no creo que exista en la forma que lo deseas.

Tenía dos pensamientos. Primero, con un split usando el modo de retención de separador, obtienes los bits intersticiales como los elementos impares en la lista de salida. Con la lista de la split, se cuenta que coinciden que se encuentra y poner de nuevo juntos cómo le gusta:

use v5.14; 

$_ = 'ab1cdef2gh3ij4k5lmn6op7qr8stu9vw10xyz'; 

my @bits = split /(\d+)/; # separator retention mode 

my @skips = qw(3 7 10); 
my $s; 
while(my($index, $value) = each @bits) { 
    # shift indices to match number (index = 2 n - 1) 
    if($index % 2 and ! (($index + 1)/2 ~~ @skips)) { 
     $s .= '^'; 
     } 
    else { 
     $s .= $value; 
     } 
    } 

me sale:

ab^cdef^gh3ij^k^lmn^op7qr^stu^vw10xyz 

pensé que me gustó mi split respuesta hasta que tuvo el segundo pensamiento. ¿Funciona state dentro de una sustitución?Parece ser que lo hace:

use v5.14; 
$_ = 'ab1cdef2gh3ij4k5lmn6op7qr8stu9vw10xyz'; 
my @skips = qw(3 7 10); 

s/(\d+)/ 
    state $n = 0; 
    $n++; 
    $n ~~ @skips ? $1 : '$' 
    /eg; 

say; 

Esto me da:

ab$cdef$gh3ij$k$lmn$op7qr$stu$vw10xyz 

No creo que usted puede conseguir mucho más simple que eso, incluso si existiera esa variable mágica.

Tuve una tercera idea que no probé. Me pregunto si state funciona dentro de una afirmación de código. Podría ser, pero luego tendría que encontrar la forma de usar uno de esos para hacer que una coincidencia falle, lo que realmente significa que tiene que omitir el bit que podría haber coincidido. Eso parece realmente complicado, que es probablemente lo que Borodin te estaba presionando para mostrar incluso en pseudocódigo.

6

Estoy ignorando por completo la utilidad real o la sabiduría de usar esto para la otra pregunta.

pensé @- o @+ puede hacer lo que quiera, ya que sostienen los desplazamientos de los partidos numerados, pero parece que el motor de expresiones regulares ya sabe cuál va a ser el último índice:

use v5.14; 

use Data::Printer; 

$_ = 'abc123abc345abc765abc987abc123'; 

my @matches = m/ 
    ([0-9]+) 
    (?{ 
     print 'Matched \$' . $#+ . " group with $^N\n"; 
     say p(@+); 
    }) 
    .*? 
    ([0-9]+) 
    (?{ 
     print 'Matched \$' . $#+ . " group with $^N\n"; 
     say p(@+); 
    }) 
    /x; 

say "Matches: @matches"; 

Esto da cuerdas que muestran el último índice como 2 aunque aún no ha coincidido con $2.

Matched \$2 group with 123 
[ 
    [0] 6, 
    [1] 6, 
    [2] undef 
] 
Matched \$2 group with 345 
[ 
    [0] 12, 
    [1] 6, 
    [2] 12 
] 
Matches: 123 345 

en cuenta que la primera vez, es $+[2] undef, de modo que uno no ha sido rellenado todavía. Es posible que puedas hacer algo con eso, pero creo que eso probablemente se aleje del espíritu de tu pregunta. Si fueras realmente elegante, podrías crear un escalar vinculado que tenga el valor del último índice definido en @+, supongo.

Cuestiones relacionadas