2010-06-30 2 views
1

Да, я знаю, я знаю, что разбор HTML с регулярными выражениями очень плох. Но я работаю с устаревшим кодом, который должен извлечь все элементы link и style со страницы html. Я бы изменил его и использовал расширение dom, но после регулярного выражения есть огромный блок кода, который опирается на способ, которым preg_match_all возвращает согласованные результаты.таблицы стилей экстрасети с помощью регулярных выражений

Скрипт использует это регулярное выражение:

$pattern = '/<(link|style)(?=.+?(?:type="(text\/css)"|>))(?=.+?(?:media="(.*?)"|>))(?=.+?(?:href="(.*?)"|>))(?=.+?(?:rel="(.*?)"|>))[^>]+?\2[^>]+?(?:\/>|<\/style>)\s*/is'; 

preg_match_all($pattern, $htmlContent, $cssTags); 

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

+0

все матчи используются? Я имею в виду тип, медиа и т. Д.? – galambalazs

+0

@ galambalazs Да, насколько я вижу, это так. – Max

+0

* Огромный блок кода * звучит как хороший кандидат на рефакторинг. Выбросьте его для правильного решения DOM. – Gordon

ответ

0

Спасибо вообще за ваши ответы, но я, наконец, переписал этот бит, используя расширение DOM. Это должно сделать его более надежным.

1

Я бы разломил эту проблему на несколько меньших. Было бы легче писать, проще поддерживать. И немного больше строк кода, конечно. Проблема с одним огромным регулярным выражением состоит в том, что есть несколько gotchas, и вход может быть недействительным, который трудно управлять в одном большом шаблоне.

/<link([^>]+)>/ 
-> extract attributes: 
    /([\w]+)\s*=\s*"([^"]*)"/ 

/<style[^>]*>(.+?)</style>/ 
-> extract inline styles 

И, наконец, объединить результаты в массив, как если бы preg_match_all произвел его.

0

Если я делал это с регулярными выражениями, например. потому что вам нужно иметь возможность обрабатывать недействительный HTML, который часто бывает затруднен с помощью соответствующего анализатора, я бы использовал отдельные регулярные выражения. Используйте одно или два регулярных выражения для получения тегов style и link и используйте другой набор регулярных выражений, чтобы получить различные атрибуты из каждого тега.

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

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

Регулярное выражение:

<(link|style)(?=[^<>]*?(?:type="(text/css)"|>))(?=[^<>]*?(?:media="([^<>"]*)"|>))(?=[^<>]*?(?:href="(.*?)"|>))(?=[^<>]*(?:rel="([^<>"]*)"|>))(?:.*?</\1>|[^<>]*>) 

PHP:

$pattern = '%<(link|style)(?=[^<>]*?(?:type="(text/css)"|>))(?=[^<>]*?(?:media="([^<>"]*)"|>))(?=[^<>]*?(?:href="(.*?)"|>))(?=[^<>]*(?:rel="([^<>"]*)"|>))(?:.*?</\1>|[^<>]*>)%si' 
0

Чтобы захватить только внешние ресурсы:

preg_match_all('#(<link\s(?:[^>]*rel="stylesheet")[^>]*>)\R?#is', $content, $matches, PREG_SET_ORDER)