Я пытаюсь создать регулярное выражение Perl, соответствующее URL-адресу, которому не предшествует знак равенства и одна одинарная или двойная кавычка (необязательно), игнорируя пробелы. Код ниже выдает ошибку: Warning: preg_replace(): Compilation failed: lookbehind assertion is not fixed length at offset 0
Я знаю, что мое регулярное выражение URL-адреса не идеально, но я больше сосредоточен на том, как выполнить отрицательный просмотр или как выразить это каким-либо другим способом.
Например, в приведенном ниже коде в совпадениях должны выводиться http://www.url1.com/ и http://www.url3.com/, но не остальные URL-адреса. Как я могу это сделать? Код ниже выдает предупреждение и не заполняет переменную $matches.
PHP-код:
$html = "
http://www.url1.com/
= ' http://www.url2.com/
'http://www.url3.com/
<a href='http://www.url4.com/'>Testing1</a>
<img src='https://url5.com'>Testing2</a>";
$url_pregex = '((http(s)?://)[-a-zA-Z()0-9@:%_+.~#?&;//=]+)';
$pregex = '(?<!\\s*=\\s*[\'"]?\\s*)'.$url_pregex;
preg_match_all('`'.$pregex.'`i', $html, $matches);
echo "Matches<br><pre>";
var_export($matches);
echo "</pre>";
Perl Regex в PHP, используя ` вместо /:
'`(?<!\\s*=\\s*[\'"]?\\s*)((http(s)?://)[-a-zA-Z()0-9@:%_+.~#?&;//=]+)`i'
@M.Eriksson К сожалению, допустил ошибку копирования и вставки и пропустил некоторые важные части. Теперь, я думаю, исправлено.






Один из способов обойти эту проблему — использовать чередование, первая часть которого соответствует URL-адресам, которым предшествует = (и необязательная кавычка), а вторая — просто соответствует URL-адресам, которые затем фиксируются. Это работает, потому что первая часть чередования всегда проверяется первой, и поэтому только URL-адреса, которым не предшествует =, будут захватываться второй частью чередования.
Для простоты я удалил группы захвата из вашего $url_pregex; если вы хотите, чтобы они были включены, вам нужно будет изменить номер группы $matches в этом коде, чтобы получить полные совпадения.
$html = "
http://www.url1.com/
= ' http://www.url2.com/
'http://www.url3.com/
<a href='http://www.url4.com/'>Testing1</a>
<img src = 'https://url5.com'>Testing2</a>";
$url_pregex = 'https?://[-a-zA-Z()0-9@:%_+.~#?&;//=]+';
$pregex = "\\s*=\\s*['\"]?\\s*$url_pregex|($url_pregex)";
preg_match_all('`' . $pregex . '`i', $html, $matches);
echo "Matches<br><pre>";
var_export(array_values(array_filter($matches[1])));
echo "</pre>";
Выход:
Matches<br><pre>array (
0 => 'http://www.url1.com/',
1 => 'http://www.url3.com/',
)</pre>
Демо на 3v4l.org
Обратите внимание, что вам нужно использовать preg_match_all, чтобы получить все совпадения в тексте.
Вам не следует раздувать выходной массив нежелательными/дисквалифицируемыми совпадениями, как показано в ответе Ника (тогда не будет необходимости очищать array_filter() и array_values()).
Чтобы использовать и выбрасывать спички, используйте (*SKIP)(*FAIL).
Я взял на себя смелость настроить ваш шаблон регулярного выражения, реализуя свой совет.
Код: (Демо)
$url_regex = 'https?://[-\w()@:%+.~#?&;/=]+';
$regex = "`\s*=\s*['\"]?\s*$url_regex(*SKIP)(*FAIL)|$url_regex`i";
var_export(preg_match_all($regex, $html, $matches) ? $matches[0] : []);
Выход:
array (
0 => 'http://www.url1.com/',
1 => 'http://www.url3.com/',
)
Если вы действительно пытаетесь проанализировать действительный HTML, то использование регулярного выражения вряд ли будет наиболее подходящим инструментом.
Пожалуйста, опубликуйте свое текущее регулярное выражение, что вы ожидаете получить от опубликованных тестовых данных и что вы получаете в настоящее время. Прочтите Как создать минимальный воспроизводимый пример и как задавать вопросы.