Почему это регулярное выражение возвращает ошибку? - PullRequest
0 голосов
/ 03 февраля 2012

Почему следующее значение true?

if(preg_match_all('%<tr.*?>.*?<b>.*?</b>.*?</tr>%ims', $contents, $x)===FALSE)
{...}

$contents извлекается с использованием file_get_contents() из этого источника .


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

if(preg_match(
           '%Areas of Study: </P>.*?<TABLE BORDER="0">(.*?)<TBODY>.*?</TBODY>.*?   </TABLE>%ims',
            $contents, $course_list)
    )
    {
        if(preg_match_all('%<TR>.*?<TD.*?>.*?<B>(.*?)</B>.*?</TD>.*?<TD.*?>.*?</TD>.*?<TD.*?>.*?<B>(.*?)</B>.*?</TD>.*?</TR>%ims',
                $course_list[0], $course_titles)
        )
        {
            ...
        }
        else 
        {
            die('<p>ERROR: first preg_match_all fails</p>');
        }

        echo '<p>INFO: Courses  found</p>';
    }
    else
    {
        die('<p>ERROR: Courses not found</p>');
    }

    if(
        preg_match_all('%<tr.*?>.*?<b>.*?first '.$college.' area of study.*?</b>.*?</tr>.*?<tr.*?>.*?<td.*?>.*?<b>(.*?) \((.*?)\).*?</b>(.*?credits.*?)</td>.*?<td.*?>(.*?<a .*?)</td>.*?</tr>%ims',
        $contents, $course_modules))
    {
        ....
    }
    else
    {
        die('<p>ERROR: Courses details/streams not found</p>');
    }

Я всегда получаю:

ИНФОРМАЦИЯ: Курсы найдены
ОШИБКА: Детали курса / потоки не найдены

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


Примечание:

Это регулярное выражение ранее работало (этобыло на самом деле сложнее).Я не уверен, имеет ли это значение , но я обновил свою версию WAMP (поэтому мой php.ini и т. Д. Был сброшен), и я поругался с настройкой во время устранения проблемы с подключением MongoDB на прошлой неделе.

Ответы [ 2 ]

3 голосов
/ 07 февраля 2012

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

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

(?ims)<tr.*?>.*?<b>.*?first science area of study.*?</b>.*?</tr>.*?<tr.*?>.*?<td.*?>.*?<b>(.*?) \((.*?)\).*?</b>(.*?credits.*?)</td>.*?<td.*?>(.*?<a .*?)</td>.*?</tr>

          course name       start      end    steps
Match #1  (Comp. Sci.)        10       275    31271
Match #2  (Bio & Chem)       276       341     6986
Match #3  (Enviro)           342       379     5944
Match #4  (Genetics)         386       416     4463
Match #5  (Chem)             417       455     5074
Match #6  (Math)             495       546    15610
Match #7  (Phys & Astro)     547       593     8617
Match #8  (no match)        gave up after 1,000,000 steps

Вы, наверное, слышали, что многие люди говорят, что не жадные регулярные выражения всегда возвращают самое короткое совпадение,так почему же этот вернул первый матч, который на 200 строк длиннее, чем остальные?Возможно, вы слышали, что они более эффективны, потому что они не отступают так сильно, так почему этот шаг занял более 30 000 шагов, чтобы завершить первый матч, и почему он эффективно заблокировал последнюю попытку, когда ни один матч не был возможен?

Во-первых, не существует такого понятия, как жадное или не жадное регулярное выражение.Только отдельные квантификаторы могут быть описаны таким образом.Регулярное выражение, в котором каждый квантификатор является жадным, не обязательно возвращает самое длинное возможное совпадение, а название «не жадное регулярное выражение» еще менее точно.Жадный или не жадный, движок регулярных выражений всегда начинает пытаться сопоставиться при первой же возможности, и он не сдается на стартовой позиции, пока не будут исследованы все возможные пути из него.

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

Теперь проверьте это регулярное выражение:

(?is)<tr[^<]*(?:<(?!/tr>|b>)[^<]*)*<b>\s*first science area of study\s*</b>.*?</tr>.*?<tr.*?>.*?<td.*?>.*?<b>(.*?) \((.*?)\).*?</b>(.*?credits.*?)</td>.*?<td.*?>(.*?<a .*?)</td>.*?</tr>

          course name       start      end    steps
Match #1  (Comp. Sci.)       209       275     9891
Match #2  (Bio & Chem)       276       341     5389
Match #3  (Enviro)           342       379     5833
Match #4  (Genetics)         386       416     4222
Match #5  (Chem)             417       455     4961
Match #6  (Math)             495       546     9899
Match #7  (Phys & Astro)     547       593     8506
Match #8  (no match)        reported failure in 139 steps

После первого </b> все будет так, как вы его написали.Эффект моих изменений заключается в том, что он не начинает сопоставляться по-настоящему, пока не найдет элемент <TR>, который содержит первый интересующий нас тег <B>:

<tr[^<]*(?:<(?!/tr>|b>)[^<]*)*<b>\s*first science area of study\s*</b>

Эта часть тратит больше всегосвоего времени жадно потребляющие символы с [^<]*, что значительно быстрее, символ за персонажем, чем не жадный .*?.Но гораздо важнее то, что практически не требуется времени, чтобы выяснить, когда больше нет совпадений.Если есть золотое правило производительности регулярных выражений, то оно таково: когда попытка матча потерпит неудачу, она должна завершиться как можно быстрее.

1 голос
/ 03 февраля 2012

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

Вы можете попробовать протестировать его, изменив регулярное выражение. Когда я тестировал его в RegexBuddy, ваше регулярное выражение соответствовало этому входу в 1216 шагах. Когда я изменил это на это:

'%<tr.*?>.*?<b>.*?</b>[^<]*(?:<(?!/?tr\b)[^<]*)*</tr>%ims'

... прошло всего 441 шаг.

...