2011-12-28 15 views
10

我正在從事一個項目,該項目從某個ftp服務器獲取文件列表。此時,它會返回文件的arrayref,或者如果傳遞了可選正則表達式引用(即qr),它將使用grep過濾列表。此外,如果qr有一個捕獲組,則它將捕獲的部分視爲版本號,並返回hashref,其中鍵爲版本,值爲文件名(如果沒有捕獲組,則返回爲數組) 。代碼如下(略有簡化)在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; 
    } 
} 

此實現嘗試創建哈希值,如果它成功返回。我的問題是,我可以檢測到qr有一個捕獲組,並且只有在嘗試創建散列時纔會發現它?

回答

18

您可以使用類似:

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

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

輸出:

2 
+2

讓我看看我是否得到它:你匹配一個空字符串反對任何東西或我的正則表達式的交替。沒有什麼讓它匹配,但它仍然填充@ +,然後捕獲組的數量作爲元素的數量。我對嗎?非常聰明! – 2011-12-28 16:51:54

+2

(更正)...然後比捕獲多一個元素(因爲$ + [0]是匹配),但由於$#+比元素數少一個,它返回正確的匹配數 – 2011-12-28 17:05:01

+0

@JoelBerger ,確切地說。 :-) – Qtax 2011-12-28 17:05:10

3

你可以使用YAPE::Regex解析正則表達式,看看是否有捕獲存在:

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

這是我所期望的,但Qtax似乎更簡單,並且有更少的代價。不過謝謝。 – 2011-12-28 16:50:00

4

請參閱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; 
} 

避免檢查模式的另一種可能性是簡單地依賴於$capture的值。在沒有捕獲的情況下成功匹配時,它將是1(Perl真值)。您可以區分它與偶爾捕獲返回1,因爲那個缺少IV標誌。

+1

相同的工具,謝謝你在這一個努力工作,但我想我會接受Qtax的答案。在我看來,依靠Perl自己的正則表達式引擎的實現似乎更加簡單,而不是解析。雖然謝謝!我確實希望答案最終會成爲這樣的東西。 – 2011-12-28 17:09:35