2011-12-28 21 views
10

Estoy trabajando en un proyecto que en un momento dado obtiene una lista de archivos de un servidor ftp. En ese momento, devuelve una matriz de archivos O, si se pasa una referencia regex opcional (es decir, qr), filtra la lista hacia abajo usando grep. Además, si ese qr tiene un grupo de captura, trata la sección capturada como un número de versión y devuelve un hashref donde las claves son las versiones y los valores son los nombres de los archivos (que se hubieran devuelto como la matriz si no hubiera grupos de captura) . El código es el siguiente (simplificado ligeramente)¿Cuenta los grupos de captura en una expresión regular qr?

sub filter_files { 
    my ($files, $pattern) = @_; 
    my @files = @$files; 
    unless ($pattern) { 
    return \@files; 
    } 

    @files = grep { $_ =~ $pattern } @files; 
    carp "Could not find any matching files" unless @files; 

    my %versions = 
    map { 
     if ($_ =~ $pattern and defined $1) { 
     ($1 => $_) 
     } else { 
     () 
     } 
    } 
    @files; 

    if (scalar keys %versions) { 
    return \%versions; 
    } else { 
    return \@files; 
    } 
} 

Esta aplicación intenta crear el hash y lo devuelve si tiene éxito. Mi pregunta es: ¿puedo detectar que el qr tiene un grupo de captura y solo intenta crear el hash si lo hace?

Respuesta

18

Se podría utilizar algo como:

sub capturing_groups{ 
    my $re = shift; 
    "" =~ /|$re/; 
    return $#+; 
} 

say capturing_groups qr/fo(.)b(..)/; 

Salida:

2 
+2

déjame ver si lo consigo: emparejas una cadena vacía con la alternancia de nada o mi expresión regular. La nada permite que coincida, pero aún se rellena @ +, que luego tiene el número de grupos de captura como la cantidad de elementos. ¿Estoy en lo cierto? ¡Muy inteligente! –

+2

(corrección) ... que tiene un elemento más que capturas (ya que $ + [0] es la coincidencia) pero como $ # + es uno menos que el número de elementos, devuelve el número correcto de coincidencias –

+0

@JoelBerger exactamente :-) – Qtax

3

usted podría utilizar YAPE::Regex a analizar la expresión regular para ver si hay una captura presentes:

use warnings; 
use strict; 
use YAPE::Regex; 

filter_files(qr/foo.*/); 
filter_files(qr/(foo).*/); 

sub filter_files { 
    my ($pattern) = @_; 
    print "$pattern "; 
    if (has_capture($pattern)) { 
     print "yes capture\n"; 
    } 
    else { 
     print "no capture\n"; 
    } 
} 

sub has_capture { 
    my ($pattern) = @_; 
    my $cap = 0; 
    my $p = YAPE::Regex->new($pattern); 
    while ($p->next()) { 
     if (scalar @{ $p->{CAPTURE} }) { 
      $cap = 1; 
      last; 
     } 
    } 
    return $cap; 
} 

__END__ 

(?-xism:foo.*) no capture 
(?-xism:(foo).*) yes capture 
+2

Esto es un poco lo que esperaba, pero Qtax parece mucho más simple y tiene menos déficits. Gracias sin embargo. –

4

Ver nparen in Regexp::Parser.

use strictures; 
use Carp qw(carp); 
use Regexp::Parser qw(); 
my $parser = Regexp::Parser->new; 

sub filter_files { 
    my ($files, $pattern) = @_; 
    my @files = @$files; 
    return \@files unless $pattern; 

    carp sprintf('Could not inspect regex "%s": %s (%d)', 
     $pattern, $parser->errmsg, $parser->errnum) 
     unless $parser->regex($pattern); 

    my %versions; 
    @files = map { 
     if (my ($capture) = $_ =~ $pattern) { 
      $parser->nparen 
       ? push @{ $versions{$capture} }, $_ 
       : $_ 
     } else { 
      () 
     } 
    } @files; 
    carp 'Could not find any matching files' unless @files; 

    return (scalar keys %versions) 
     ? \%versions 
     : \@files; 
} 

Otra posibilidad para evitar la inspección de la pauta es simplemente confiar en el valor de $capture. Será 1 (valor real de Perl) en el caso de una coincidencia exitosa sin captura. Puede distinguirlo de la captura ocasional que devuelve 1 porque ese carece de la bandera IV.

+1

igual que para la herramienta, gracias por hacer el trabajo duro en este caso, pero creo que voy a aceptar la respuesta de Qtax. Me parece que depender de la implementación del motor de expresiones regulares de Perl parece más a prueba de tontos que de análisis. ¡Gracias! Realmente esperaba que las respuestas terminaran siendo algo como esto. –

Cuestiones relacionadas