2010-06-17 118 views
0

我有一些數據,我在Perl中解析,並且將在不久的將來添加更多不同格式的數據。我想要做的是編寫一個易於使用的函數,我可以傳遞一個字符串和一個正則表達式,並且它會在圓括號中返回任何東西。它的工作是這樣的(僞):在Perl中匹配n個圓括號正則表達式

sub parse { 
    $data = shift; 
    $regex = shift; 

    $data =~ eval ("m/$regex/") 
    foreach $x ($1...$n) 
    { 
    push (@ra, $x); 
    } 
    return \@ra; 
} 

然後,我可以這樣稱呼它:

@subs = parse ($data, '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)'); 

正如你可以看到,有一對夫婦的與此代碼的問題。我不知道eval是否會起作用,'foreach'肯定不起作用,不知道有多少個括號,我不知道要循環多少次。

這對於分割太複雜了,所以如果還有其他功能或可能性,我可以忽略,請告訴我。

感謝您的幫助!

回答

6

在列表上下文中,正則表達式將返回所有括號匹配的列表。

因此,所有你需要做的就是:

my @matches = $string =~ /regex (with) (parens)/; 

並假設它相匹配,@matches將兩個拍攝組的陣列。

因此,使用您正則表達式:

my @subs = $data =~ /^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/; 

而且,當你有很長的正則表達式,Perl中有x改性劑,其收盤正則表達式分隔符後面。 x修飾符允許您在正則表達式中添加空格和換行符以提高可讀性。

如果您擔心可能爲零長度的捕獲組,您可以通過@subs = grep {length} @subs傳遞匹配將它們濾除。

+0

如果你不知道這個正則表達式是否有parens,並且如果它不是(默認的整個匹配的字符串)而不想返回任何東西,可以添加一個額外的集合:'$ string =〜/(regex)/'並從結果中丟棄它。 – ysth 2010-06-18 01:30:54

+0

grep會過濾出實際上在匹配中沒有使用的parens,但是不會是零長度的(這將被定義和「」) – ysth 2010-06-18 01:32:19

+0

@ysth =>你是對的,修復。 – 2010-06-18 13:17:45

0

您試圖用正則表達式解析一個複雜的表達式 - 這是一個工作不足的工具。回想一下,正則表達式不能解析更高級的文法。對於直覺而言,任何可能嵌套的表達式都不能用正則表達式進行分析。

+0

Perl的使用regexen是不規則的。你可以使用'(?? {blah})',儘管這不是完全推薦的做法。 – muhmuhten 2010-06-17 22:38:39

+0

perl的正則表達式引擎也支持遞歸,這使得它可以很容易地匹配嵌套的結構 – 2010-06-17 22:44:30

+0

真 - 許多正則表達式實現實際上可以解析超過一組常規語言,但這不是一致的。如果您需要解析語法 - 請使用適當的語法分析器。 – 2010-06-17 22:45:56

0

當您想要在括號對內找到文本時,您想要使用Text::Balanced

但是,這不是你想要做的,所以它不會幫助你。

+1

儘管問題的名稱,它似乎並沒有像OP實際上尋找匹配嵌套parens,只是使用一個正則表達式,可以有任何數量的順序捕獲組 – 2010-06-17 23:00:30

+0

對不起,我應該說'括號分組'的「括號」。 – 2010-06-21 16:59:27

1

然後,我可以這樣調用:相反

@subs = parse($data, 
      '^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)'); 

,調用它:

parse($data, 
    qr/^"([0-9]+)",([^:]*):(\W+):([A-Z]{3}[0-9]{5}),ID=([0-9]+)/); 

而且,你的任務會更簡單,如果你可以使用named captures (即Perl 5.10和更高版本)。下面是一個例子:

#!/usr/bin/perl 

use strict; use warnings; 

my %re = (
    id => '(?<id> [0-9]+)', 
    name => '(?<name> \w+)', 
    value => '(?<value> [0-9]+)', 
); 

my @this = (
    '123,one:12', 
    '456,two:21', 
); 

my @that = (
    'one:[12],123', 
    'two:[21],456', 
); 

my $this_re = qr/$re{id} , $re{name} : $re{value}/x; 
my $that_re = qr/$re{name} : \[$re{value}\] , $re{id} /x; 

use YAML; 

for my $d (@this) { 
    print Dump [ parse($d, $this_re) ]; 
} 

for my $d (@that) { 
    print Dump [ parse($d, $that_re) ]; 
} 

sub parse { 
    my ($d, $re) = @_; 
    return unless $d =~ $re; 
    return my @result = @+{qw(id name value)}; 
} 

輸出:

--- 
- 123 
- one 
- 12 
--- 
- 456 
- two 
- 21 
--- 
- 123 
- one 
- 12 
--- 
- 456 
- two 
- 21
+0

謝謝你,這是很高興知道! – 2010-06-21 21:55:27