سؤال

تنهد ، إعادة المتاعب مرة أخرى.

لقد اتبعت في $text:

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

and 

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

لدي تعبير regex:

$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 و regexps 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] 

أفترض أن المشكلة هي في جزء من lookarounds و url regex. أين خطأي؟

أريد أن

يحل محل http://www.google.com مع "كان هناك رابط" ، ولكن اترك كما هو [urlhttp://www.google.com [/url"

انا احصل

http://www.google.com تم استبداله بـ "كان هناك رابط" و [urlhttp://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 = "http://stackoverflow.com/questions/2482921/regexp-exclusion";

$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

?>
هل كانت مفيدة؟

المحلول

على افتراض أنني أفهمك ، كنت ترغب في استبدال جميع عناوين URL في إدخال $ الخاص بك ، بكلمات "الرابط كان هنا" ، ما لم يكن عنوان URL ضمن علامات عنوان URL أو IMG BBCode. السبب في أن التأكيدات التي لا تعمل بها هي أن هذه الأجزاء تتطابق فعليًا مع نمط عنوان URL الجشع الخاص بك (وهو ما أنا متأكد من أن الكثير من الأشياء التي لا تعنيها). إن كتابة نمط يتطابق مع أي عنوان URL صالح (بما في ذلك سلسلة الاستعلام) ضمن نص آخر ولن يتطابق مع العلامات المرفقة به بالضرورة أبسط الأمور. خاصة وأن نمطك الحالي يحتوي على http: // أو ftp: // على أنه اختياري.

الطريقة الوحيدة التي من المحتمل أن تحصل عليها أي نجاح هي اتخاذ قرار بشأن مجموعة صارمة من القواعد التي تشكل عنوان URL.

نصائح أخرى

من الصعب فهم سؤالك تمامًا ، لكن يبدو أنك تقوم برمز BBCode العكسي. لذا، اتركه بمفرده إذا كان محاطًا بعلامات؟ إذا كان هذا هو الحال ، فأعتقد أنه سيكون لديك مشكلة مثيرة للاهتمام على يديك لأن regexes url معقدة.

أعتقد أنك قد تجعل هذا أكثر تعقيدًا مما يجب أن يكون. بدلاً من ذلك ، أود تغيير أي شيء بين رمز BBC. هذا ما أعتقد أنه يجب أن يحدث:

  1. ابحث عن جزء السلسلة [url]
  2. القبض على أي شيء يستمر
  3. قم بإنهاء الالتقاط عندما يتم رؤية مقطع السلسلة [/url]

هذا regex سهلة:

$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;

أعلم أن هذا ليس بالضبط ما طلبته (في الواقع ، على الأرجح عكس ذلك تمامًا) ، لكنه سيحقق نفس النتيجة ويكون أسهل بكثير.

ربما يمكنك محاولة باستخدام lookaheads السلبية مع هذا regex ، لكنني لست متأكدًا من أنه سيعطيك نتائج مناسبة:

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

ملاحظة واحدة مهمة: هذا لا يعقد إدخال المستخدم. تأكد من قيامك بذلك ، لكنني سأفصل بين المنطق ، لذا من السهل جدًا رؤية ما تفعله وأين تفعل ذلك. أود أيضًا استخدام مكتبة للقيام بذلك لأنها أسهل وربما أكثر أمانًا.

يشبه regexp العمل النهائي:

(?<!\[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. لم يتم العثور على طريقة أخرى لحل هذه المشكلة.

أين خطأي؟

حسنا ، و أسوأ الخطأ هو المظهر. ليس من الضروري ، وهو يجعل المهمة أكثر صعوبة مما يجب أن تكون. على افتراض أن العلامات الموجودة تتشكل جيدًا ، فلن تحتاج إلى أن تهتم بالبحث عن علامة الافتتاح ؛ ووجودها ضمني من خلال وجود علامة الإغلاق.

تحرير: لدى Regex العديد من المشكلات الأخرى إلى جانب Lookbehind ، لكن لا يبدو من المفيد محاولة إصلاحه. بدلاً من ذلك ، أمسك regex من مكتبة Regexbuddy المدمجة من regexes المفيدة ، وأضفت Lookahead إليها.

جرب هذا regex (أو أراه في العمل ideone):

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

فقط لأن المشكلة يمكن أن تكون موصوفة فيما يتعلق بالتطلع إلى الأمام أو للخلف ، أو السابق أو المتابع ، وما إلى ذلك ، لا يعني أنه يجب عليك تصميم regex بهذه الطريقة. يجب على Lookbehind على وجه الخصوص أبداً كن أول أداة تصل إليها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top