Извлечение основного текста HTML-документа с использованием PHP - PullRequest
4 голосов
/ 06 февраля 2011

Я знаю, что для этой цели лучше использовать 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 ]

11 голосов
/ 06 февраля 2011

Проблема в том, что в вашей строке новые строки, где. в шаблоне совпадает только с одной строкой, вам нужно добавить модификатор / 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>');

Вы получаете правильную позицию (начиная с позиции 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 (символы, которые вы должны прочитать), но у вас есть только 16 печатных символов текста между и и 4 непечатаемых символа (новая строка после и новая строка до ). И вот проблема, вы должны сгруппировать вычисления (расставить приоритеты) следующим образом:

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

оценивается как 51 - (25 + 6) = 51 - 31 = 20 (16 + 4).

:) Надеюсь, это поможет вам понять, почему расстановка приоритетов важна. (Извините, что ввел вас в заблуждение насчет перевода строки, он действителен только в приведенном выше примере с регулярным выражением).

4 голосов
/ 06 февраля 2011

Лично я бы не использовал регулярные выражения.

<?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>

2 голосов
/ 06 февраля 2011

Проблема в ваших 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>
1 голос
/ 06 февраля 2011

Возможно, кто-то уже нашел вашу ошибку, я не прочитал все ответы.
Алгебра неверна.

код здесь

Кстати,в первый раз, увидев 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)
       );
...