2012-07-19 138 views
2

我的搜索文本如下。匹配所有出現的字符串

... 
... 
var strings = ["aaa","bbb","ccc","ddd","eee"]; 
... 
... 

它包含了許多行(實際上是一個JavaScript文件),但需要在可變,即AAA,BBB,CCC,DDD,EEE

以下是Perl代碼,或解析值使用PHP在底部

my $str = <<STR; 
    ... 
    ... 
    var strings = ["aaa","bbb","ccc","ddd","eee"]; 
    ... 
    ... 
STR 

my @matches = $str =~ /(?:\"(.+?)\",?)/g; 
print "@matches"; 

我知道上面的腳本將匹配所有瞬間,但它將解析的其他線路也串(「XYZ」)。所以,我需要檢查字符串VAR串=

/var strings = \[(?:\"(.+?)\",?)/g 

使用上述正則表達式將解析AAA

/var strings = \[(?:\"(.+?)\",?)(?:\"(.+?)\",?)/g 

使用以上,將獲得AAABBB。所以爲了避免正則表達式的重複,我使用瞭如下的'+'量詞。

/var strings = \[(?:\"(.+?)\",?)+/g 

但是我只拿到了EEE,所以我的問題是,爲什麼我EEE只有當我使用 '+' 量詞?

更新1:使用PHP preg_match_all(做得到:-)更多的關注)

$str = <<<STR 
    ... 
    ... 
    var strings = ["aaa","bbb","ccc","ddd","eee"]; 
    ... 
    ... 
STR; 

preg_match_all("/var strings = \[(?:\"(.+?)\",?)+/",$str,$matches); 
print_r($matches); 

更新2:爲什麼它匹配EEE?由於(?:\"(.+?)\",?)+的貪婪。通過消除貪婪/var strings = \[(?:\"(.+?)\",?)+?/aaa將匹配。 但爲什麼只有一個結果呢?有沒有什麼辦法可以通過使用單個正則表達式來實現?

回答

2

這裏有一個單一的正則表達式的解決方案:

/(?:\bvar\s+strings\s*=\s*\[|\G,)\s*"([^"]*)"/g 

\G是零寬度斷言,在以前的比賽結束位置相匹配(或字符串的開頭,如果它是第一場比賽的嘗試)。因此,這就像:

var\s+strings\s*=\s*[\s*"([^"]*)" 

...在第一次嘗試,那麼:

,\s*"([^"]*)" 

...在那之後,但每場比賽的開始正是最後一個離開的。

這是demo in PHP,但它也可以在Perl中使用。

+0

是的,它的工作。謝謝... :-)。但是,你能解釋一下爲什麼它對'/ var strings = \ [(?:\「(。+?)\」,?)+?/'? – Jithin 2012-07-19 12:17:34

+0

如果您從Perl版本中離開'g',或者調用'preg_match'而不是'preg_match_all',則會看到您獲得相同的結果;你實際上只做一場比賽。在該匹配中,捕獲組中的部分被多次應用,每次覆蓋最後一次傳遞的結果。我正在做多個比賽,並分別保存每場比賽的結果。 – 2012-07-19 13:20:28

1

因爲+告訴它重複一次或多次括號內的確切東西(?:"(.+?)",?)。所以它會匹配"eee"字符串,結束然後查找該字符串的重複,它找不到。

use YAPE::Regex::Explain; 
print YAPE::Regex::Explain->new(qr/var strings = \[(?:"(.+?)",?)+/)->explain(); 

The regular expression: 

(?-imsx:var strings = \[(?:"(.+?)",?)+) 

matches as follows: 

NODE      EXPLANATION 
---------------------------------------------------------------------- 
(?-imsx:     group, but do not capture (case-sensitive) 
         (with^and $ matching normally) (with . not 
         matching \n) (matching whitespace and # 
         normally): 
---------------------------------------------------------------------- 
    var strings =   'var strings = ' 
---------------------------------------------------------------------- 
    \[      '[' 
---------------------------------------------------------------------- 
    (?:      group, but do not capture (1 or more times 
          (matching the most amount possible)): 
---------------------------------------------------------------------- 
    "      '"' 
---------------------------------------------------------------------- 
    (      group and capture to \1: 
---------------------------------------------------------------------- 
     .+?      any character except \n (1 or more 
           times (matching the least amount 
           possible)) 
---------------------------------------------------------------------- 
    )      end of \1 
---------------------------------------------------------------------- 
    "      '"' 
---------------------------------------------------------------------- 
    ,?      ',' (optional (matching the most amount 
          possible)) 
---------------------------------------------------------------------- 
)+      end of grouping 
---------------------------------------------------------------------- 
)      end of grouping 
---------------------------------------------------------------------- 

一個簡單的例子是:只有

my @m = ('abcd' =~ m/(\w)+/g); 
print "@m"; 

打印d。這是由於:

use YAPE::Regex::Explain; 
print YAPE::Regex::Explain->new(qr/(\w)+/)->explain(); 

The regular expression: 

(?-imsx:(\w)+) 

matches as follows: 

NODE      EXPLANATION 
---------------------------------------------------------------------- 
(?-imsx:     group, but do not capture (case-sensitive) 
         (with^and $ matching normally) (with . not 
         matching \n) (matching whitespace and # 
         normally): 
---------------------------------------------------------------------- 
    (      group and capture to \1 (1 or more times 
          (matching the most amount possible)): 
---------------------------------------------------------------------- 
    \w      word characters (a-z, A-Z, 0-9, _) 
---------------------------------------------------------------------- 
)+      end of \1 (NOTE: because you are using a 
          quantifier on this capture, only the LAST 
          repetition of the captured pattern will be 
          stored in \1) 
---------------------------------------------------------------------- 
)      end of grouping 
---------------------------------------------------------------------- 

如果您在捕獲組上使用量詞,將只使用最後一個實例。


這裏是一個可行的辦法:

my $str = <<STR; 
    ... 
    ... 
    var strings = ["aaa","bbb","ccc","ddd","eee"]; 
    ... 
    ... 
STR 

my @matches; 
$str =~ m/var strings = \[(.+?)\]/; # get the array first 
my $jsarray = $1; 
@matches = $array =~ m/"(.+?)"/g; # and get the strings from that 

print "@matches"; 

更新: 單行的解決方案(雖然不是一個單一的正則表達式)將是:

@matches = ($str =~ m/var strings = \[(.+?)\]/)[0] =~ m/"(.+?)"/g; 

但這是非常難以理解的imho。

+0

是的,這很酷。謝謝。但有沒有什麼辦法可以在一個正則表達式中完成。 – Jithin 2012-07-19 11:31:27

+0

@Jithin你想要單個正則表達式的原因是什麼?這很難閱讀,除此之外,所有小的正則表達式的工作速度都快於單個 – gaussblurinc 2012-07-19 11:39:58

+0

@simbabque在您給出的簡單示例中,由於貪婪,它僅匹配_d_。改變你的表達式爲'm /(\ w)+?/ g'會匹配所有的,即'a b c d'。但是爲什麼它在問題更新2中不適用於組正則表達式? – Jithin 2012-07-19 11:42:28

2

您可能更喜歡此解決方案,它首先使用/g修飾符查找字符串var strings = [。這將\G設置爲在[之後立即匹配下一個正則表達式,該正則表達式緊跟在出現雙引號字符串之後,可能以逗號或空格開頭。

my @matches; 

if ($str =~ /var \s+ strings \s* = \s* \[ /gx) { 
    @matches = $str =~ /\G [,\s]* "([^"]+)" /gx; 
} 

儘管使用/g修改您正則表達式,因爲那裏是沒有var strings = [第二次出現/var strings = \[(?:\"(.+?)\",?)+/g只匹配一次。每次比賽都會返回捕獲變量$1,$2,$3等值的列表,當匹配完成時,/(?:"(.+?)",?)+/(不需要轉義雙引號)將多個值捕獲到$1中,只留下最終值。你需要寫如上所述的東西,每個比賽只能將一個值記錄到$1

+0

對'\ G'提示爲+1。 – simbabque 2012-07-19 15:10:50

相關問題