preg_match для извлечения mailto на привязке

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

этот шаблон: (.*)<a\s(.*?)(.*)\s*href\=['"]mailto:([-a-z0-9_]+)@([a-z0-9-]+).([a-z]+)['"]>(.*)</a>(.*)

Работает в тренере регулярных выражений, но не работает с PHP.

Код:

preg_match("'(.*)<a (.*?)(.*) *href\=['\"]mailto:([-a-z0-9_]+)@([a-z0-9-]+).([a-z]+)['\"]>(.*)</a>(.*)'si", "<a href=\"mailto:[email protected]\"">Some email</a>", $matches);

print_r($matches);

Так почему же это не работает в php?


person Gertjan    schedule 23.11.2010    source источник
comment
В качестве примечания: вам нужно будет добавить + в качестве символа в свой класс символов :([-a-z0-9_]+), потому что некоторые люди используют их для фильтрации триггеров в адресах электронной почты, например, [email protected]   -  person Keng    schedule 23.11.2010
comment
Все эти .* приведут к ужасной производительности.   -  person Gumbo    schedule 23.11.2010
comment
примечание: хотя и редко, но вполне приемлемо иметь адрес электронной почты вида: hell.o\@[email protected] Возможно, вам лучше использовать более простое регулярное выражение, если только электронные письма не связаны с безопасностью. . Зависит от того, что вы делаете с ними.   -  person DampeS8N    schedule 23.11.2010
comment
@Гамбо .*$ сделал бы это? в основном все до конца строки?   -  person Keng    schedule 23.11.2010
comment
@ DampeS8N: Нет, hell.o\@[email protected] недействителен (как для \‍, так и для @). Но "hell.o@world"@example.com действителен.   -  person Gumbo    schedule 23.11.2010
comment
" будет закодировано в атрибуте HTML.   -  person bcosca    schedule 23.11.2010
comment
@stillstanding: Будет? Что, если бы использовались одинарные кавычки?   -  person Gumbo    schedule 23.11.2010
comment
@Gumbo: И большинство парсеров, которые я только что нашел, чтобы проверить все это, говорят, что оба неверны. Именно поэтому электронные письма отстой.   -  person DampeS8N    schedule 23.11.2010
comment
@Gumbo: я хотел сказать, что должен, иначе HTML будет неправильно проанализирован   -  person bcosca    schedule 23.11.2010
comment
@ DampeS8N: существует разница между синтаксисом, определенным в спецификации, и синтаксисом, который фактически используется/разрешен.   -  person Gumbo    schedule 23.11.2010
comment
@stillstanding: Нет, <a href='"foo bar"@example.com'> в порядке.   -  person Gumbo    schedule 23.11.2010
comment
@Gumbo: это не проблема. Но что-то вроде <a href="<?php echo $email; ?>"> столкнется с проблемами, если $email='"hell.o@world"@example.com';   -  person bcosca    schedule 23.11.2010


Ответы (3)


PCRE PHP требует, чтобы регулярное выражение было заключено в разделители, которые отделяют шаблон от необязательных модификаторов< /а>. В этом случае используется первый небуквенно-цифровой символ (т. е. '), поэтому на самом деле шаблон представляет собой просто (.*)<a (.*?)(.*) *href\=[, а остальные обрабатываются как модификаторы. И это недопустимое регулярное выражение, поскольку [ не экранировано должным образом, а остальные также не являются допустимыми модификаторами.

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

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

Лучше использовать правильный анализатор HTML, который возвращает DOM, который можно запрашивать, как библиотека DOM PHP:

$doc = new DomDocument();
$doc->loadHTML($str);
foreach ($doc->getElementsByTagName("a") as $a) {
    if ($a->hasAttribute("href")) {
        $href = trim($a->getAttribute("href"));
        if (strtolower(substr($href, 0, 7)) === 'mailto:') {
            $components = parse_url($href);
        }
    }
}
person Gumbo    schedule 23.11.2010
comment
-1. Ответьте на конкретный вопрос, затем прочитайте лекцию о том, почему DOM лучше. Для спрашивающего может быть непросто понять новую библиотеку или провести рефакторинг своей ситуации достаточно быстро, независимо от того, насколько мы можем чувствовать, что есть лучший способ. - person Shabbyrobe; 24.11.2010
comment
@Shabbyrobe: я добавил объяснение. - person Gumbo; 24.11.2010

Ваш разделитель - это цитата ', и в регулярном выражении есть несколько ее экземпляров:

preg_match("'(.*)<a (.*?)(.*) *href\=['\"]mailto:([-a-z0-9_]+)@([a-z0-9-]+).([a-z]+)['\"]>(.*)</a>(.*)'si", "<a href=\"mailto:[email protected]\"">Some email</a>", $matches);
                                      ^                                              ^

Избегайте их (например: \') или измените разделитель.

person netcoder    schedule 23.11.2010

person    schedule
comment
Это не удается для чего-то вроде <a name="…">…</a><map name="…"><area href="…" alt="…"></map<a href="mailto:[email protected]">…</a>. - person Gumbo; 23.11.2010