danyim's answer is accurate, though it might not fit your needs exactly, as noted in the comments. Also, his solution was php-based. From scanning your tag participation, I'm guessing that you'd actually prefer a javascript solution (so I'll provide both!).
First, refactoring his php:
function isValidURL($url) {
$regex = "((https?|ftp)\:\/\/)?"; // SCHEME
$regex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?"; // User and Pass
$regex .= "((([a-z][a-z0-9-.]*)\.([a-z]{2,3}))|(([12]?[0-9]?[0-9]\.){4}))"; // Host or IP
$regex .= "(\:[0-9]{2,5})?"; // Port
$regex .= "(\/([a-z0-9+\$_-]\.?)+)*\/?"; // Path
$regex .= "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?"; // GET Query
$regex .= "(#[a-z_.-][a-z0-9+\$_.-]*)?"; // Anchor
return preg_match($regex, lcase($url));
}
Note that I modified the return to perform an lcase operation before checking the url. You could also use a case-insensitive flag on the regex to prevent the need for this. As noted, there are a number of parts to this that may or may not be valid for your use-cases. Specifically, you may not ever have a situation in which you want to accept a url that includes a username/pw, or that is from a static IP. You can modify the regex to exclude whatever parts of the match are never valid by removing the related line. Also, here is a second option for the //Host or IP
line, to make it host only:
$regex .= "([a-z][a-z0-9-.]*)\.([a-z]{2,3})"; // Host only
And now the same thing in javascript (combined together because js handles regex different than strings...adjustments will be easier to make in the php version and then mimic into here):
function isValidURL(url) {
var regex = /((https?|ftp)\:\/\/)?([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?((([a-z][a-z0-9-.]*)\.([a-z]{2,3}))|(([12]?[0-9]?[0-9]\.){4}))(\:[0-9]{2,5})?(\/([a-z0-9+\$_-]\.?)+)*\/?(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?(#[a-z_.-][a-z0-9+\$_.-]*)?/i
return (url.match(regex));
}