Является ли регулярное выражение правильным инструментом для поиска строки HTML? - PullRequest
4 голосов
/ 19 ноября 2009

У меня есть PHP-скрипт, который извлекает некоторый контент с сервера, но проблема в том, что строка, в которой находится контент, меняется каждый день, поэтому я не могу просто выделить конкретную строку. Тем не менее, содержимое содержится в div, который имеет уникальный идентификатор. Возможно ли (и является ли это наилучшим способом) регулярное выражение для поиска этого уникального идентификатора и затем передать строку, на которой он находится, обратно в мой сценарий?

Пример:

HTML-файл:

<html><head><title>Example</title></head>
<body>
<div id="Alpha"> Blah blah blah </div>
<div id="Beta"> Blah Blah Blah </div>
</body>
</html>

Допустим, я ищу строку с открывающим тегом div с идентификатором alpha. Код должен возвращать 3, потому что в третьей строке находится div с идентификатором alpha.

Ответы [ 7 ]

3 голосов
/ 19 ноября 2009

Обычно НЕТ . Но если вы уверены, что div всегда будет одной строкой или , то внутри него нет другого div , вы можете использовать его без проблем. Что-то вроде /<div id=\"mydivid\">(.*?)</div>/ или что-то подобное.

В противном случае DOMDocument будет более разумным способом.

РЕДАКТИРОВАТЬ См. Ваш пример HTML. Мой ответ будет " ДА ". RegEx - очень хороший инструмент для этого.

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

Вот примерный код PHP для его извлечения. (просто чтобы дать представление)

$HTML =
"<html><head><title>Example</title></head>
<body>
<div id=\"Alpha\"> Blah blah blah </div>
<div id=\"Beta\"> Blah Blah Blah </div>
</body>
</html>";

$ID = "Alpha";

function GetLineOfDIV($HTML, $ID) {
    $RegEx_Alpha = '/\n(<div id="'.$ID.'">.*?<\/div>)\n/m';
    $Index       = preg_match($RegEx_Alpha, $HTML, $Match, PREG_OFFSET_CAPTURE);
    $Match       = $Match[1]; // Only the one in '(...)'
    if ($Match == "")
        return -1;

    //$MatchStr    = $Match[0]; Since you do not want it, so we comment it out.
    $MatchOffset = $Match[1];

    $StartLines = preg_split("/\n/", $HTML, -1, PREG_SPLIT_OFFSET_CAPTURE);
    foreach($StartLines as $I => $StartLine) {
        $LineOffset = $StartLine[1];
        if ($MatchOffset <= $LineOffset)
            return $I + 1;
    }
    return count($StartLines);
}

echo GetLineOfDIV($HTML, $ID);

Надеюсь, я дам вам кое-какую идею.

3 голосов
/ 19 ноября 2009

С риском предоставления большего количества голосов за Джеффа, который уже пересек горы безумия ... см. Здесь

Аргумент бушует взад и вперед, но ... это простой одноразовый или малоиспользуемый скрипт, который вы пишете, тогда обязательно используйте regex, если он более сложный и должен быть надежным с небольшими изменениями в будущем тогда предложить использовать анализатор HTML. HTML - отвратительный, часто нерегулярный зверь, который можно приручить. Используйте подходящий инструмент для работы ... возможно, в вашем случае это регулярное выражение, или, может быть, это полноценный парсер.

3 голосов
/ 19 ноября 2009
1 голос
/ 19 ноября 2009

Поскольку здесь важен номер строки, а не фактическое содержимое div, я был бы склонен вообще не использовать регулярные выражения. Я, вероятно, explode() строка в массив и перебрать этот массив в поисках вашего маркера. Вот так:

<?php
$myContent = "[your string of html here]";
$myArray = explode("\n", $myContent);
$arraylen = count($myArray); // So you don't waste time counting the array at every loop
$lineNo = 0;
for($i = 0; $i < $arraylen; $i++)
{
     $pos = strpos($myArray[$i], 'id="Alpha"');
     if($pos !== false)
     {
          $lineNo = $i+1;
          break;
     }
}
?>

Отказ от ответственности: у меня нет готовой установки php для тестирования, поэтому может потребоваться некоторая отладка.

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


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


Редактировать # 2: Ой, эй ... вот мои два цента:

"/<div.*?id=\"Alpha\".*?>.*?(<div.*//div>)*.*?//div>/m"

(<div.*//div>) сообщает механизму регулярных выражений, что он может найти вложенные теги div и просто включить их в совпадение, если найдет их, а не просто остановиться на первом </div>. Однако это решает проблему только при наличии только одного уровня вложенности. Если есть еще, то регулярное выражение не для вас извините: (.

/m также заставляет механизм регулярных выражений игнорировать разрывы строк, поэтому вам не нужно портить выражения с помощью [\S\s] везде.

Опять же, извините, у меня нет среды для тестирования в данный момент, поэтому вам может понадобиться отладка.

Приветствие Иэн

1 голос
/ 19 ноября 2009

Тот факт, что задействован уникальный идентификатор, звучит многообещающе, но, поскольку это будет DIV, а не обязательно одна строка HTML, будет трудно создать регулярное выражение и обычные возражения против разбора HTML с помощью применяются регулярные выражения.

Не рекомендуется.

1 голос
/ 19 ноября 2009

Вместо RegEx используйте синтаксический анализатор, созданный специально для обработки (грязного) HTML. Это сделает ваше приложение менее хрупким, если HTML-код немного изменится, и вам не придется вручную создавать пользовательский RegEx каждый раз, когда вы хотите извлечь новый фрагмент данных.

См. Эту страницу переполнения стека: Зрелые парсеры HTML для PHP

0 голосов
/ 19 ноября 2009

@ OP, поскольку ваши требования настолько просты, вы можете просто использовать строковые методы

$f = fopen("file","r");
if($f){
    $s="";
    while( !feof($f) ){
        $i+=1;
        $line = fgets($f,4096);        
        if (stripos($line,'<div id="Alpha">')!==FALSE){
            print "line number: $i\n";
        }
    }
    fclose($f);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...