Сложность PHP Regex - PullRequest
       15

Сложность PHP Regex

1 голос
/ 24 мая 2009

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

Например, в данном случае ниже, как я могу получить регулярное выражение для получения "<div id="contentleft">"?

<div id="content"> 


<div id="contentleft">  <SCRIPT language=JavaScript>

Я пытался

id="content">(.*?)<SCRIPT

но это не работает.

Ответы [ 6 ]

2 голосов
/ 24 мая 2009
$s = '<div id="content">

<div id="contentleft">  <SCRIPT language=JavaScript>';

if( preg_match('/id="content">(.*?)<SCRIPT/s', $s, $matches) )
    print $matches[1]."\n";

Точка, по умолчанию, соответствует всему, кроме новых строк. /s заставляет его соответствовать всему.

Но на самом деле используйте DOM-парсер. Вы можете пройтись по дереву или использовать запрос XPath. Думайте об этом как о регулярных выражениях для XML.

$s = '<div id="content">

<div id="contentleft">  <SCRIPT language=JavaScript>';

// Load the HTML
$doc = new DOMDocument();
$doc->loadHTML($s);

// Use XPath to find the <div id="content"> tag's descendants.
$xpath = new DOMXPath($doc);
$entries = $xpath->query("//div[@id='content']/descendant::*");

foreach( $nodes as $node ) {
    // Stop when we see <script ...>
    if( $node->nodeName == "script" )
        break;

    // do what you want with the content
}

XPath очень мощный. Вот несколько примеров.

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

1 голос
/ 24 мая 2009

Взгляните на модификаторы PCRE: http://ar2.php.net/manual/en/reference.pcre.pattern.modifiers.php

Вы можете применить модификатор s, например '/id="content">(.*?)<SCRIPT/s' (хотя, будьте осторожны, поскольку он меняет способ работы ^ и $ тоже.

В противном случае вы можете сделать '/id="content">((.|\n)*?)<SCRIPT/'

РЕДАКТИРОВАТЬ: упс, неправильный модификатор ...

0 голосов
/ 24 мая 2009
$dom = new DOMDocument();
$dom->strictErrorChecking = false;
$dom->loadHTML($html_str);

$xpath = new DOMXPath($dom);
$div = $xpath->query('div[@id="content"]')->item(0);

Пожалуйста, исправьте мое выражение xpath - не уверен, будет ли оно работать ...

0 голосов
/ 24 мая 2009

Ну, это многострочная проблема, поэтому взгляните на модификаторы шаблона:

м (PCRE_MULTILINE) По умолчанию PCRE обрабатывает строку темы как состоящий из одной "линии" символы (даже если это на самом деле содержит несколько новых строк). Начало строки "метасимвол (^) соответствует только в начале строки, в то время как метасимвол "конец строки" ($) соответствует только в конце строки, или перед завершающим переводом строки (если модификатор D не установлен). Это так же, как Perl.

Когда этот модификатор установлен, «запуск» конструкций линии "и" конец строки " соответствовать сразу после или непосредственно перед любой новой строкой в предметная строка соответственно тоже как в самом начале, так и в конце. Это эквивалентно модификатору Perl's / m. Если в нём нет символов \ n строка темы, или нет вхождений ^ или $ в шаблоне, устанавливая это Модификатор не имеет эффекта.

s (PCRE_DOTALL) Если этот модификатор установить, метасимвол точки в шаблон соответствует всем персонажам, в том числе и новые строки. Без этого, новые строки исключены. Этот модификатор эквивалентно модификатору Perl's / s. отрицательный класс, такой как [^ a] всегда соответствует символу новой строки, независимо от настройки этого Модификатор.

из http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

0 голосов
/ 24 мая 2009

Другое решение без регулярных выражений:

$start = 'id="content">';
$end = '<SCRIPT';
if (($startPos = strpos($str, $start)) !== false &&
    ($endPos = strpos($str, $end, $startPos+1)) !== false) {
    $substr = substr($str, $startPos, $endPost-$startPos);
}
0 голосов
/ 24 мая 2009

Попробуйте

id="content">((?:.|\n)*?)<SCRIPT

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

В качестве альтернативы:

(?<=id="content">)(?:.|\n)*?(?=<SCRIPT)

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

Первое регулярное выражение соответствует вашему подходу, расширенному разрешением \n. Ваш матч будет в группе 1, вам нужно только обрезать его.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...