4

この目的にはDOMを使用する方がよいことはわかっていますが、次の方法でテキストを抽出してみましょう。

<?php


$html=<<<EOD
<html>
<head>
</head>
<body>
<p>Some text</p>
</body>
</html>
EOD;


        preg_match('/<body.*?>/', $html, $matches, PREG_OFFSET_CAPTURE);

        if (empty($matches))
            exit;

        $matched_body_start_tag = $matches[0][0];
        $index_of_body_start_tag = $matches[0][1];

        $index_of_body_end_tag = strpos($html, '</body>');


        $body = substr(
                        $html,
                        $index_of_body_start_tag + strlen($matched_body_start_tag),
                        $index_of_body_end_tag - $index_of_body_start_tag + strlen($matched_body_start_tag)
        );

echo $body;

結果はここで見ることができます:http://ideone.com/vH2FZ

ご覧のとおり、予想よりも多くのテキストが表示されています。

substr($string, $start, $length)関数の正しい長さを取得するために、私が理解していないことがあります。

$index_of_body_end_tag - $index_of_body_start_tag + strlen($matched_body_start_tag)

この式には何の問題もありません。

誰かが問題がどこにあるかを親切に提案できますか?

みなさん、ありがとうございました。

編集:

皆様、本当にありがとうございました。私の脳にはただのバグがあります。あなたの答えを読んだ後、私は今問題が何であるかを理解しました、それは次のいずれかでなければなりません:

  $index_of_body_end_tag - ($index_of_body_start_tag + strlen($matched_body_start_tag));

または:

  $index_of_body_end_tag - $index_of_body_start_tag - strlen($matched_body_start_tag);
4

4 に答える 4

11

問題は、文字列に新しい行があることです。パターンでは1行のみに一致するため、を作成するには/s修飾子を追加する必要があります。複数行に一致させる

これが私の解決策です、私はそれをこのように好みます。

<?php

$html=<<<EOD
<html>
<head>
</head>
<body buu="grger"     ga="Gag">
<p>Some text</p>
</body>
</html>
EOD;

    // get anything between <body> and </body> where <body can="have_as many" attributes="as required">
    if (preg_match('/(?:<body[^>]*>)(.*)<\/body>/isU', $html, $matches)) {
        $body = $matches[1];
    }
    // outputing all matches for debugging purposes
    var_dump($matches);
?>

編集:コードが失敗する理由をよりよく説明するために、回答を更新しています。

あなたはこの文字列を持っています:

<html>
<head>
</head>
<body>
<p>Some text</p>
</body>
</html>

すべて問題ないように見えますが、実際には各行に非印刷文字(改行文字)があります。53個の印刷可能な文字と7個の印刷不可能な文字があります(新しい行、\ n ==実際には新しい行ごとに2文字)。

コードのこの部分に到達すると、次のようになります。

$index_of_body_end_tag = strpos($html, '</body>');

</ body>の正しい位置(位置51から開始)を取得しますが、これにより新しい行がカウントされます。

したがって、このコード行に到達すると、次のようになります。

$index_of_body_start_tag + strlen($matched_body_start_tag)

31(新しい行を含む)と評価され、次のようになりました。

$index_of_body_end_tag - $index_of_body_start_tag + strlen($matched_body_start_tag)

これは51-25+6 = 32(読む必要のある文字)と評価されますが、<body>と</ body>の間に16文字の印刷可能なテキストと4つの印刷不可能な文字(<body>の後の改行とnew </ body>の前の行)。そして、ここに問題があります。次のように計算をグループ化(優先順位付け)する必要があります。

$index_of_body_end_tag - ($index_of_body_start_tag + strlen($matched_body_start_tag))

51-(25 + 6)= 51-31 = 20(16 + 4)と評価されます。

:)これが優先順位付けが重要である理由を理解するのに役立つことを願っています。(改行について誤解を招くことをお詫びします。これは、上記の正規表現の例でのみ有効です)。

于 2011-02-06T02:02:50.567 に答える
4

個人的には、正規表現は使用しません。

<?php

$html = <<<EOD

<html>
    <head>
        <title>Example</title>
    </head>
    <body>
        <h1>foobar</h1>
    </body>
</html>

EOD;

$s = strpos($html, '<body>') + strlen('<body>');
$f = '</body>';

echo trim(substr($html, $s, strpos($html, $f) - $s));

?>

戻り値<h1>foobar</h1>

于 2011-02-06T02:07:58.443 に答える
2

問題はsubstr、終了インデックスの計算にあります。あなたはずっと差し引くべきです:

$index_of_body_end_tag - $index_of_body_start_tag - strlen($matched_body_start_tag)

しかし、あなたはやっています:

+ strlen($matched_body_start_tag)

とはいえ、を使用してそれを行うことができることを考えると、それは少しやり過ぎのようpreg_match ですs修飾子を使用して、新しい行間で一致することを確認する必要があります。

preg_match('/<body[^>]*>(.*?)<\/body>/s', $html, $matches);
echo $matches[1];

出力:

<p>Some text</p>
于 2011-02-06T01:59:23.730 に答える
1

誰かがすでにあなたのエラーを見つけたでしょう、私はすべての返事を読んでいませんでした。
代数が間違っています。

コードはこちら

ところで、ideone.comを初めて見たときは、かなりかっこいいです。

$body = substr( 
          $html, 
          $index_of_body_start_tag + strlen($matched_body_start_tag),
          $index_of_body_end_tag - ($index_of_body_start_tag + strlen($matched_body_start_tag))
        );

また ..

$body = substr(
          $html,
          $index_of_body_start_tag + strlen($matched_body_start_tag),
          $index_of_body_end_tag - $index_of_body_start_tag - strlen($matched_body_start_tag)
       );
于 2011-02-06T05:33:45.783 に答える