За исключением регулярного выражения URL - PullRequest
2 голосов
/ 14 августа 2010

Вздох, снова испытай неприятности.

У меня есть в $text:

[img]http://www.site.com/logo.jpg[/img]

and 

[url]http://www.site.com[/url]

У меня есть выражение регулярного выражения:

$text = preg_replace("/(?<!(\[img\]|\[url\]))([http|ftp]+:\/\/)?\S+[^\s.,>)\];'\"!?]\.+[com|ru|net|ua|biz|org]+\/?[^<>\n\r ]+[A-Za-z0-9](?!(\[\/img\]|\[\/url\]))/","there was link",$text);

Смысл в том, чтобы заменить URL только в том случае, если перед ним не стоит [img] или [url], а за ним не следует [/img] или [/url]. На выходе предыдущего примера получаю:

there was link

and

there was link

Регулярные выражения URL, lookbehind и lookforward работают по отдельности.

$text = "[img]bash.org/logo.jpg[/img]";

$text = preg_replace("/(?<!(\[img\]|\[url\]))bash.org(?!(\[\/img\]|\[\/url\]))/","there was link",$text);

echo $text leaves everything as is and gives me [img]bash.org/logo.jpg[/img] 

Полагаю, проблема в комбинации поисков и URL-выражения. Где моя ошибка?

ХОЧУ

заменить http://www.google.com на "была ссылка", но оставить как есть "[url] http://www.google.com[/url]"

Я ПОЛУЧУ

http://www.google.com заменено на "была ссылка" и [url] http://www.google.com[/url] заменено на "была ссылка"

ЗДЕСЬ КОД PHP ДЛЯ ТЕСТИРОВАНИЯ

<?php

$text = "[url]http://www.google.com[/url] <br><br> http://www.google.com"; 
         // should NOT be changed                  //should be changed    

$text = preg_replace("/(?<!\[url\])([http|ftp]+:\/\/)?\S+[^\s.,>)\];'\"!?]\.+[com|ru|net|ua|biz|org]+\/?[^<>\n\r ]+[A-Za-z0-9](?!\[\/url\])/","there was link",$text);

echo $text;

echo '<hr width="100%">';

$text = ":) :-) 0:) 0:-) :)) :-))";

$text = preg_replace("/(?<!0):-?\)(?!\))/","smiley",$text);

echo $text; // lookarounds work

echo '<hr width="100%">';

$text = "/2158549/isklychenie-regulyarnogo-vyrazheniya";

$text = preg_replace("/([http|ftp]+:\/\/)?\S+[^\s.,>)\];'\"!?]\.+[com|ru|net|ua|biz|org]+\/?[^<>\n\r ]+[A-Za-z0-9]/","it's a link to stackoverflow",$text);

echo $text; // URL pattern works fine

?>

Ответы [ 4 ]

2 голосов
/ 14 августа 2010

Предполагая, что я вас понимаю, вы хотите заменить все URL-адреса в вашем вводе $ словами "ссылка была здесь", если только URL не был в тегах url или img bbcode.Причина, по которой косвенные утверждения не работают, заключается в том, что эти части на самом деле совпадают с вашим очень жадным шаблоном URL (который, я уверен, делает много вещей, которые вы не имеете в виду).Написание шаблона, который будет соответствовать любому действительному URL (включая строку запроса) внутри другого текста и который также не будет соответствовать прикрепленным к нему тегам, не обязательно является самым простым делом.Тем более, что ваш текущий шаблон имеет http: // или ftp: // как необязательный.

Единственный способ добиться успеха - принять строгий набор правил, составляющих URL.

0 голосов
/ 16 августа 2010

Где моя ошибка?

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

РЕДАКТИРОВАТЬ: у вашего регулярного выражения есть несколько других проблем, кроме внешнего вида, но, похоже, не стоит пытаться это исправить. Вместо этого я взял регулярное выражение из встроенной библиотеки полезных регулярных выражений RegexBuddy и добавил к нему предварительный просмотр.

Попробуйте это регулярное выражение (или посмотрите его в действии на ideone ):

'_\b(?>
     (?>www\.|ftp\.|(?:https?|ftp|file)://)  # scheme or subdomain
     [-+&@#/%=~|$?!:,.\w]*[+&@#/%=~|$\w]     # everything else
   )(?!\[/(?:img|url)\])
 _x'

То, что проблема может быть описана как 1017 * с точки зрения просмотра вперед или назад, предшествования или следования и т. Д., Не означает, что вы должны разработать регулярное выражение таким образом. В частности, никогда не должен быть первым инструментом, к которому вы обращаетесь.

0 голосов
/ 14 августа 2010

Окончательное рабочее регулярное выражение выглядит следующим образом:

(?<!\[img\]|\[url\])((^|\s)([\w-]+://|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))(?!\[\/img\]|\[/url\])

Пример:

<?php

$text = "

[img]http://google.com/logo.jpg[/img]

[img]www.google.com/logo.jpg[/img]

[img]http://www.google.com/logo.jpg[/img]

[url]http://google.com/logo.jpg[/url]

[url]www.google.com/logo.jpg[/url]

[url]http://www.google.com/logo.jpg[/url]

www.google.com/logo.jpg

http://google.com/logo.jpg

http://www.google.com/logo.jpg

";

$text = nl2br($text);


$text = preg_replace("'(?<!\[img\]|\[url\])((^|\s)([\w-]+://|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))(?!\[\/img\]|\[/url\])'i","<font color=\"#ff0000\">link</font>",$text);

echo $text;

?>

выходы:

[img]http://google.com/logo.jpg[/img]

[img]www.google.com/logo.jpg[/img]

[img]http://www.google.com/logo.jpg[/img]

[url]http://google.com/logo.jpg[/url]

[url]www.google.com/logo.jpg[/url]

[url]http://www.google.com/logo.jpg[/url]

link

link

link

Хитрость заключается в замене только ссылок, начинающихся с ^ или \ s. Других способов решения этой проблемы не найдено.

0 голосов
/ 14 августа 2010

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

Я думаю, что вы можете сделать это более сложным, чем нужно. Вместо этого я бы изменил все, что находится между BBcode. Вот что я думаю должно произойти:

  1. найти сегмент строки "[url]"
  2. захватить все, что происходит
  3. завершить захват, когда будет виден сегмент строки "[/ url]"

Это простое регулярное выражение:

$string = "[url]http://www.google.com[/url] <br><br> http://www.google.com"; 

$replace = "there was link";
$text = preg_replace_all($regex,$replace,$text);
echo $text;

Я знаю, что это не совсем то, о чем вы просили (на самом деле, возможно, с точностью до наоборот), но это достигнет того же результата и будет намного проще.

Вероятно, вы можете попробовать , используя отрицательные взгляды с этим регулярным выражением, но я не уверен, что это даст вам надлежащие результаты:

$regex = "#(?!\[url\])(.*)(?!\[/url\])#";

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

...