34196


正規表現で苦戦しております。

[code]

    '<h2>foo</h2>
        randomstr
        <span>randamstr</span>
    <h2>bar</h2>
        <div>randomstr</div>
    <h2>baz</h2>
        randomstr'
    
[/code]

このような文字列を

[code]

    [
        [0] => '<h2>foo</h2>randomstr<span>randamstr</span>',
        [1] => '<h2>bar</h2><div>randomstr</div>',
        [2] => '<h2>baz</h2>randomstr',
    ]
    
[/code]

このようにpreg_match_allなどで抜き出したいのですが、どのように正規表現を書けばよいのでしょうか？


CC BY-SA 3.0
2017-04-21T18:43:02.597
34195
2017-04-21T21:08:04.683
12543
question
php 正規表現
正規表現で"<h2>〜","<h2>〜"と抜き出すには。


まずは`"<h2>〜"`の`〜`が何を表すのかきちんと定義してください。

ここでは、

  * 直近の`<h2>`の手前まで

または(`<h2>`がもう存在しなければ)

  * 文字列の末尾まで

を表すものとしておきます。

PHPの現在の標準正規表現エンジンであるPCREでは、

「直近の」→非貪欲な量指定子`*?`  
「…の手前」→[assertion](http://php.net/manual/ja/regexp.reference.assertions.php)(バッファを消費しないマッチング)

が使えます(最近の正規表現実装なら大抵使えるはず)ので、比較的自然に正規表現パターンとして表現することができます。

[code]

    $pattern = '/<h2>.*?(?=<h2>|$)/s';
    
[/code]

* * *

(実行例)

[code]

    $html = '<h2>foo</h2>
        randomstr
        <span>randamstr</span>
    <h2>bar</h2>
        <div>randomstr</div>
    <h2>baz</h2>
        randomstr';
    $pattern = '/<h2>.*?(?=<h2>|$)/s';
    $matches = [];
    if( preg_match_all($pattern, $html, $matches) ) {
      var_dump($matches);
    }
    
[/code]

出力:

>
[code]

>     array(1) {
>       [0]=>
>       array(3) {
>         [0]=>
>         string(54) "<h2>foo</h2>
>         randomstr
>         <span>randamstr</span>
>     "
>         [1]=>
>         string(38) "<h2>bar</h2>
>         <div>randomstr</div>
>     "
>         [2]=>
>         string(26) "<h2>baz</h2>
>         randomstr"
>       }
>     }
>  
[/code]

Macに乗っているのは古いPHP 5.6ですが、PCRE周りの仕様は変更されていないので、PHP 7,
7.1でも同じ結果が得られるはずです。なお、最初の仮定があなたの必要とされる動作と異なる場合には、ご質問内容を編集して要件をより明確化するようにしてください。


CC BY-SA 3.0
2017-04-21T21:08:04.683
34196
2017-04-21T21:08:04.683
13972
34195
answer