比如有这样一个字符串: <div><ul id="test1"><li>aaaaa</li><li>bbbbb</li></ul><ul id="test2"><li>cccccc</li><li>ddddd</li></ul></div>我想一次性将id为test1的ul标签里的li标签包含的文本都提取出来。写了如下的表达式:
<ul[^>]*id="test1"[^>]*>(<li>(?:<text>[^<]*)</li>)+[^<]*</ul>,用preg_match来匹配,因为整个表达式我只需要匹配一次就足够了。这个表达式执行完毕后捕获组text里只保存了bbbbb,而没有保存aaaaa。为什么会这样?难道php的捕获组只能保存最后一次捕获的内容?
听说php的正则也不支持平衡组的,我也试过php下的平衡组,是没成功。会不会是因为上面这个原因?平衡组需要能够压栈,可php捕获第二次的时候,就将第一次的数据丢了?要完成上面的匹配,我用php只能分步进行,第一步先匹配出id为test1的ul包含的内容,第二步再用preg_match_all来匹配里面的所有li包含的文本。不知道有没有什么办法用php可以不用分步,一次性匹配出来的?谢谢!

解决方案 »

  1.   

    preg_match_all 试试或者用用这个试试 <li>.*</li>
      

  2.   

    preg_match_all没用,因为本来整个表达式就只匹配一次。id为test1的ul在整个字符串里只有一个。
    用<li>.*</li>的话,一者是贪婪匹配,会匹配出aaaaa</li><li>bbbbb。另外我想要的是aaaaa和bbbbb,希望返回的结果中match数组的test(捕获组名)元素也为一个数组,包含aaaaa和bbbbb两个值。之所以test组会成功捕获两次,是因为我的表达式里用了 (<li>(?:<text>[^<]*)</li>)+,是这个+在起作用。
    我现在返回的match结果是:
    Array
    (
        [0] => <ul id="test1"><li>aaaaa</li><li>bbbbb</li></ul>
        [1] => <li>bbbbb</li>
        [text] => bbbbb
        [2] => bbbbb
    )
      

  3.   

    顺便更正一下,主帖里的正则表达式不小心打错,(?:<text> 处应为 (?<text 多了一个: 。我自己测试的时候没打错,发帖的时候才打错的。
      

  4.   

    可以看到键名为1的元素只保存了 <li>bbbbb</li> ,而实际在匹配的时候,肯定也匹配到了 <li>aaaaa</li>的,因为第0个元素里出现了。而除了 <li>(?<text>[^<]*)</li> 之外,我的表达式里没有其他部分可以匹配到 <li>aaaaa</li> 的。
      

  5.   

    你的问题和前几天某个坛友问的问题一样
    看看这个帖子
    http://topic.csdn.net/u/20111123/13/90853673-e439-44bc-8f2e-f75873903951.html
      

  6.   

    谢谢,的确是一样的。
    不过我用这种方法来尝试却仍然出现问题:
    $reg = '~(?:<ul id="test1">|\G)\K<li>(?<text>\w+)</li>~';
    $str = '<div><ul id="test1"><li>aaaaa</li><li>bbbbb</li></ul><ul id="test2"><li>cccccc</li><li>ddddd</li></ul></div>';
    preg_match($reg,$str,$match);
    print_r($match);
    打印的结果是:
    Array
    (
        [0] => <li>aaaaa</li>
        [text] => aaaaa
        [1] => aaaaa
    )
    居然只匹配了第一个li。
    这是怎么回事?
      

  7.   

    preg_match 改成 preg_match_all 即可。
      

  8.   

    多谢,解决了。
    原来重新寻找搜索头需要在preg_match_all模式下才有效。