I'd recommend you look into the preg_replace_callback function instead.
Rather than trying to match different subsets of urls, for each different site, just match them all! Then, in code check a specific capturing group to check the base of the url
So, in php code, if the url starts with facebook, replace the url with the facebook shortcode, and so on.
Here's your regex, slighly modified to capture the domain. Remember to escape your literal periods. This just captures up to the first <
/
?
or whitespace for the domain, then until the first <
or whitespace for the rest of the URL. You might have to modify this if you find anything that this doesn't work for.
((https?://)(www\.)|(https?://)|(www\.))([^</\?\s]+)[^<\s]*
And now some php code. Recall that $matches[0] will have the full match, and $matches[6] will have the 6th caputuring group - in this case ([^</\?\s]+)
, the domain part
$post = preg_replace_callback(
'/((https?:\/\/)(www\.)|(https?:\/\/)|(www\.))([^<\/\?\s]+)[^<\s]*/',
function ($matches) {
switch($matches[6]){
case 'facebook.com':
return "[facebook]" . $matches[0] . "[/facebook]";
case 'youtube.com':
return "[youtube]" . $matches[0] . "[/youtube]";
case 'soundcloud.com':
return "[soundcloud]" . $matches[0] . "[/soundcloud]";
default:
return "[url]" . $matches[0] . "[/url]";
}
},
$post);