How versatile do you want it to be?
$uchar = '([a-zA-Z0-9!*\'(),$_.+-]|%[\da-fA-F][\da-fA-F])';
$xchar = '([;\/?:@&=a-zA-Z0-9!*\'(),$_.+-]|%[\da-fA-F][\da-fA-F])';
// URL Schemeparts for ip-based protocols
$domainlabel = '[a-zA-Z\d]([a-zA-Z\d.]*[a-zA-Z\d])?';
$toplabel = '[a-zA-Z]([a-zA-Z\d.]*[a-zA-Z\d])?';
$host = '(('.$domainlabel.'\.)*'.$toplabel.'|\d+\.\d+\.\d+\.\d+)';
$hostport = $host.'(:\d+)?';
$urlpath = '('.$xchar.')*';
$login = '(('.$uchar.'|[;?&=])*(:('.$uchar.'|[;?&=])*)?@)?'.$hostport;
// The generic form of a URL is:
$genericurl = '([a-z\d+.-])+:(('.$xchar.')*|\/\/'.$login.'(\/'.$urlpath.')?)';
// The scheme is in lower case; interpreters should be case-insensitive.
// Specific predefined schemes are defined here; new schemes may be
// registered with IANA.
// The predefined schemes:
// FTP (see also RFC959)
$fsegment = '('.$uchar.'|[?:@&=])*';
$fpath = $fsegment.'(\/'.$fsegment.')*';
$ftpurl = 'ftp:\/\/'.$login.'(\/'.$fpath.'(;type=[AIDaid])?)?';
// FILE
$fileurl = 'file:\/\/('.$host.'|localhost)\/'.$fpath.'';
// HTTP (see also RFC2616)
$search = '('.$uchar.'|[;:@&=])*';
$hsegment = '('.$uchar.'|[;:@&=])*';
$httpurl = 'http:\/\/'.$hostport.'(\/'.$hsegment.'(\/'.$hsegment.')*(\?'.$search.')?)?';
// GOPHER (see also RFC1436)
$gopherurl = 'gopher:\/\/'.$hostport.'(\/(($xchar)*(($xchar)*(%09'.$search.'(%09($xchar)*)?)?)?)?)?';
// MAILTO (see also RFC822)
$mailtourl = 'mailto:('.$xchar.')+'; // Further defined in RFC822
// NEWS (see also RFC1036)
$group = '[a-zA-Z]([a-zA-Z\d.+_-])*';
$newsurl = 'news:(\*|'.$group.'|('.$uchar.'|[;\/?:&=])+@'.$host.')';
// NNTP (see also RFC977)
$nntpurl = 'nntp:\/\/'.$hostport.'\/'.$group.'(\/\d+)?';
// TELNET
$telneturl = 'telnet:\/\/'.$login.'\/?';
// WAIS (see also RFC1625)
$waisurl = '(wais:\/\/'.$hostport.'\/('.$uchar.')*)(\?'.$search.'|\/('.$uchar.')*\/('.$uchar.')*)?';
// PROSPERO
$psegment = '('.$uchar.'|[?:@&=])*';
$prosperourl = 'prospero:\/\/'.$hostport.'\/'.$psegment.'(\/'.$psegment.')*(;('.$uchar.'|[?:@&])*=('.$uchar.'|[?:@&])*)*';
// New schemes follow the general syntax
$otherurl = $genericurl;
$url = $httpurl.'|'.$ftpurl.'|'.$newsurl.'|'.$nntpurl.'|'.$telneturl.'|'.$gopherurl.'|'.$waisurl.'|'.$mailtourl.'|'.$fileurl.'|'.$prosperourl.'|'.$otherurl;
Eg., for http URLs only...
'/http:\/\/((a-z\d?.)a-z?|\d+.\d+.\d+.\d+)(:\d+)?(\/([a-z0-9!\'(),$.+;:@&=-]|%[\da-f][\da-f])(\/([a-z0-9!\'(),$.+;:@&=-]|%[\da-f][\da-f]))(\?([a-z0-9!\'(),$_.+;:@&=-]|%[\da-f][\da-f]))?)?/i'
(I think. Too tired to have any confidence.)