2010-02-05 116 views
8

的比赛我有一个字符串,它可能是这个样子:PHP正则表达式 - 重复一组

$r = 'Filed under: <a>Group1</a>, <a>Group2</a>'; 

这里是正则表达式我使用至今:

preg_match_all("/Filed under: (?:<a.*?>([\w|\d|\s]+?)<\/a>)+?/", $r, $matches); 

我想在()内部的正则表达式继续进行匹配,如最后指定的+?。但它不会这样做。 ::感叹::

任何想法。我知道必须有一种方法可以在一个正则表达式中完成此操作,而不是将其分解。

回答

5

尝试:

<?php 

$r = 'Filed under: <a>Group1</a>, <a>Group2</a>, <a>Group3</a>, <a>Group4</a>'; 

if(preg_match_all("/<a.*?>([^<]*?)<\/a>/", $r, $matches)) { 
    var_dump($matches[1]); 
} 

?> 

输出:

array(4) { 
    [0]=> 
    string(6) "Group1" 
    [1]=> 
    string(6) "Group2" 
    [2]=> 
    string(6) "Group3" 
    [3]=> 
    string(6) "Group4" 
} 

编辑:

既然你要在搜索中包括“下一篇”唯一标识匹配的字符串,你可以试试这个,我不知道它是否可以使用单个调用的preg_match

// Since you want to match everything after 'Filed under' 
if(preg_match("/Filed under:(.*)$/", $r, $matches)) { 
    if(preg_match_all("/<a.*?>([^<]*?)<\/a>/", $matches[1], $matches)) { 
     var_dump($matches[1]); 
    } 
} 
+0

谢谢,但我真的需要使用“Filed under:”标志。虽然我的示例文本是基本的,但我解析的实际文件却非常复杂,而归档于:是我必须使用的唯一唯一标识符。幸运的是,它在文件末尾,所以我可以一直匹配到最后。 – 2010-02-05 04:22:08

+0

足够接近。 :) 谢谢。 – 2010-02-05 05:21:03

1

我想要正则表达式在()中继续进行匹配,并用+指定。最后。

+?是惰性限定符 - 它将匹配倍可能。换句话说,就是一次。

如果你想匹配多次,你想要一个贪婪的量词 - +

另请注意,您的正则表达式不太适用 - 只要遇到标签之间的逗号,匹配就会失败,因为您没有考虑到它。这可能需要纠正。

+0

对,我试过了+量词。这也失败了。而且我也考虑过,[恐惧],恐怕我不知道该如何设置,因为第二或第三场比赛可能没有逗号。我做了这个尝试: [code] preg_match_all(“/提起下:(?:([\ w | \ d | \ s] +?)<\/a>。*?)+ /”,$ r ,$匹配); [/ code] – 2010-02-05 04:15:26

+0

嗯,评论看起来不太漂亮。 – 2010-02-05 04:15:46

+0

@Senica:您可以像在问题和答案中一样使用反引号来格式化代码,但如果代码很长或很复杂,您应该编辑您的问题并将其放在那里。你上面包含的代码有点评论。 – 2010-02-05 09:25:09

2
$r = 'Filed under: <a>Group1</a>, <a>Group2</a>' 
$s = explode("</a>",$r); 
foreach ($s as $k){ 
    if ($k){ 
     $k=explode("<a>",$k); 
     print "$k[1]\n"; 
    } 
} 

输出

$ php test.php 
Group1 
Group2 
+1

有时RegExes真的是做某事的最佳方式...... – SoapBox 2010-02-05 04:15:55

+1

最好与否,取决于个人。如果不需要复杂的正则表达式,那么对我来说是最好的,无论对于我自己还是对维护它的人来说都是如此。 – ghostdog74 2010-02-05 04:20:26

+0

正如我在上面的评论中所解释的那样,我不能使用爆炸....例如,有些情况下没有逗号并且只有一个组。二,虽然我的例子很简单,但这是一个复杂的文件。 标签也不那么简单。三,我需要提交下:属性作为使用爆炸肯定会返回不需要的值。 – 2010-02-05 04:44:25

8
完成

只是为了好玩这里有一个正则表达式将与一个preg_match_all工作:

'%(?:Filed under:\s*+|\G</a>)[^<>]*+<a[^<>]*+>\K[^<>]*%` 

或者,在一个更可读的格式:

'%(?: 
     Filed under: # your sentinel string 
    |     
     \G    # NEXT MATCH POSITION 
     </a>   # an end tag 
) 
    [^<>]*+   # some non-tag stuff  
    <a[^<>]*+>  # an opening tag 
    \K    # RESET MATCH START 
    [^<>]+   # the tag's contents 
%x' 

\G与下一场比赛尝试开始的位置相匹配,这通常是上一次成功比赛结束的位置(但如果前一场比赛是零长度,则会前进一场)。这意味着正则表达式将不匹配从</a>开始的子字符串,直到后的与至少一次从Filed under:开始匹配。

在哨兵字符串或结束标记匹配后,[^<>]*+<a[^<>]*+>消耗了一切,直至包括下一个开始标记。然后\K欺骗起始位置,以便匹配(如果有的话)似乎在<a>标签后面开始(这看起来像是一个积极的后视,但更灵活)。最后,[^<>]+匹配标签的内容并将匹配位置带到结束标签,以便\G可匹配。

但是,正如我所说的,这只是为了好玩。如果你不需要在一个正则表达式中完成这项工作,你最好使用一个像@codaddict一样的多步骤方法;它更具可读性,更灵活,更易于维护。

\K reference
\G reference

编辑:虽然我给的引用是为Perl的文档,这些功能是由PHP支持,太 - 或者,更准确地说,是由PCRE库。我认为Perl文档好一点,但是您也可以在PCRE manual中阅读这些内容。

+0

我不知道'\ K'。有趣!关于'\ G'的一个小记录 - 您指的是“上一个匹配”,这是可以的,并且指向“下一个匹配”,这有点令人困惑(特别是当您链接的Perl示例完全具有误导性时 - 它*设置*代码中的下一个位置 - **,这与默认行为**)非常不同。简单地说 - '\ G'指的是当前匹配尝试开始的位置。它也不是准确的''将总是匹配'Filed under:'之后 - 它也可以匹配字符串的开头,for例如', Group2':http://ideone.com/aTjrm。 – Kobi 2011-08-21 04:22:47

+0

(顺便说一句,我来自这里:http://stackoverflow.com/questions/5982451/regex-capturing-a-repeated-group/7135730#7135730) – Kobi 2011-08-21 04:27:10

+0

嗯,实际上,我对'\ G'的定义是不好。 – Kobi 2011-08-21 04:41:32