Najlepiej używać wzorców do URL wziętych z internetu. Ten jest całkiem niezły (nie przeraź się):
Kod
^(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?$
Czyli dla Twojego przypadku wyglądałoby to tak:
Kod
(?:^|[^"])(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?
Powinien działać idealnie. Na początek wzorca dałem fragment, który przepuści takie linki, które są na samym początku łańcucha znaków lub mają przed sobą dowolny znak inny niż cudzysłów.
A co do (?: ... ) - wszystkie funkcje preg_XXX traktują w specjalny sposób fragmenty wzorców zapisane w nawiasie.
preg_match do wyników swojego działania (zmiennej podanej jako 3-ci parametr) dodaje wszystko co znajdzie, a oprócz tego wszystkie fragmenty w nawiasach. Jak dasz (?: ... ) zamiast normalnego nawiasu, to zawartość tego nawiasu nie jest przechwytywana. Pobaw się i porównaj wyniki tych instrukcji:
preg_match('#Ala ma ([a-z]+)\.#', 'Ala ma kota.', $matches);
oraz:
preg_match('#Ala ma (?:[a-z]+)\.#', 'Ala ma kota.', $matches);