Как определить, разделяет ли тег HTML несколько строк - PullRequest
3 голосов
/ 29 августа 2008

Я пишу сценарий PHP, который включает в себя очистку веб-страниц. В настоящее время скрипт анализирует страницу построчно, но он прерывается, если есть тег, который занимает несколько строк, например

<img src="example.jpg"
alt="example">

Если худшее приходит к худшему, я мог бы предварительно обработать страницу, удалив все разрывы строк, а затем вставив их заново на ближайшем >, но это похоже на кучу.

В идеале я мог бы обнаружить тег, который охватывает строки, соединить только те строки и продолжить обработку.
Так какой же лучший способ обнаружить это?

Ответы [ 6 ]

7 голосов
/ 29 августа 2008

Это одна из моих любимых мозолей: никогда парсит HTML вручную. Никогда анализирует HTML с помощью регулярных выражений. Никогда анализирует HTML с помощью сравнения строк. Всегда использовать анализатор HTML для анализа HTML - вот для чего они здесь.

Прошло много времени с тех пор, как я создал любой PHP, но быстрый поиск обнаружил этот синтаксический анализатор PHP5 *

2 голосов
/ 29 августа 2008

Не пишите парсер, используйте чужой: DOMDocument :: loadHTML - это всего лишь один, я думаю, что есть много других.

1 голос
/ 29 августа 2008

Возможно, для будущих проектов я буду использовать библиотеку синтаксического анализа, но это вроде как вопрос под рукой. Это мое текущее решение. rstrpos является строкой, но в обратном направлении. Пример использования:

for($i=0; $i<count($lines); $i++)
{
    $line = handle_mulitline_tags(&$i, $line, $lines);
}

И вот эта реализация:

function rstrpos($string, $charToFind, $relativePos)
{
    $searchPos = $relativePos;
    $searchChar = '';

    while (($searchChar != $charToFind)&&($searchPos>-1))
    {
        $newPos = $searchPos-1;
        $searchChar = substr($string,$newPos,strlen($charToFind));
        $searchPos = $newPos;
    }

    if (!empty($searchChar))
    {
        return $searchPos;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

function handle_multiline_tags(&$i, $line, $lines)
{
    //if a tag is opened but not closed before a line break,

    $open = rstrpos($line, '<', strlen($line));
    $close = rstrpos($line, '>', strlen($line));
    if(($open > $close)&&($open > -1)&&($close > -1))
    {
        $i++;
        return trim($line).trim(handle_multiline_tags(&$i, $lines[$i], $lines));
    }
    else
    {
        return trim($line);
    }
}

Возможно, это можно каким-то образом оптимизировать, но для моих целей этого достаточно.

1 голос
/ 29 августа 2008

Ну, это не ответ на вопрос, а скорее мнение, но ...

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

Будет два типа курса:

  • Отметить элементы, которые сразу закрываются, например,
  • Пометить элементы, для которых требуется отдельный закрывающий тэг, например,

    text

Вы можете сразу увидеть преимущество использования этой стратегии в случае тегов абзаца (p): будет проще анализировать многострочные абзацы, а не отслеживать, где находится закрывающий тег.

0 голосов
/ 29 августа 2008

Если вам нужно придерживаться текущего метода синтаксического анализа, и это регулярное выражение, вы можете использовать многострочный флаг"m", чтобы охватить несколько строк.

0 голосов
/ 29 августа 2008

Почему бы вам не прочитать строку и установить ее в строку, а затем проверить строку на наличие открытий и закрытий тегов. Если тег занимает более одной строки, добавьте следующую строку в строку и переместите часть перед открывающая скобка для вашей обработанной строки. Затем просто проанализируйте весь файл, делая это. Это не красиво, но должно работать.

...