我相信其他答案会拒绝一些有效的网址(如大写的域名或长子域)并允许一些无效的网址(如http://www.-example-.com 或 www.%@&.com)。我尝试考虑一些额外的 url 语法规则(不涉及国际化)。
function isUrlValid(userInput) {
var regexQuery = "^(https?://)?(www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6}(/[-\\w@\\+\\.~#\\?&/=%]*)?$";
var url = new RegExp(regexQuery,"i");
return url.test(userInput);
}
var input = ["https://o.sub-domain.example.com/foo/bar?foo=bar&boo=far#a%20b",
"HTTP://EX-AMPLE.COM",
"example.c",
"example-.com"];
for (var i in input) document.write(isUrlValid(input[i]) + ": " + input[i] + "<br>");
为了还允许 IP 地址和端口号,正则表达式为:
"^(https?://)?(((www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6})|((\\d{1,3}\\.){3}\\d{1,3}))(:\\d{2,4})?(/[-\\w@\\+\\.~#\\?&/=%]*)?$"
为了也允许查询字符串在域名和问号之间没有斜线(理论上是不允许的,但在大多数实际情况下都可以),正则表达式是:
"^(https?://)?(((www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6})|((\\d{1,3}\\.){3}\\d{1,3}))(:\\d{2,4})?((/|\\?)[-\\w@\\+\\.~#\\?&/=%]*)?$"
为了确保每个 % 后跟一个十六进制数字,正则表达式为:
"^(https?://)?(((www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6})|((\\d{1,3}\\.){3}\\d{1,3}))(:\\d{2,4})?((/|\\?)(((%[0-9a-f]{2})|[-\\w@\\+\\.~#\\?&/=])*))?$"
(注:正如John Wu在评论中提到的,有有效的single-letter domains)。