从字符串中提取主机名

我想匹配的只是一个URL的根,而不是一个文本字符串的整个URL。考虑到:

http://www.youtube.com/watch?v=ClkQA2Lb_iE
http://youtu.be/ClkQA2Lb_iE
http://www.example.com/12xy45
http://example.com/random

我想让最后两个实例解析到www.example.comexample.com域。

我听说正则表达式很慢,这将是我在页面上的第二个正则表达式,所以如果有办法做到没有正则表达式,请告诉我。

我正在寻找这个解决方案的JS/jQuery版本。

347448 次浏览

试试这个:

var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
var domain = matches && matches[1];  // domain will be null if no match is found

如果你想从结果中排除端口,请使用下面的表达式:

/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i

编辑:为了防止特定的域匹配,使用负前向。(?!youtube.com)

/^https?\:\/\/(?!(?:www\.)?(?:youtube\.com|youtu\.be))([^\/:?#]+)(?:[\/:?#]|$)/i

解析URL可能很棘手,因为您可以使用端口号和特殊字符。因此,我建议使用像parseUri这样的东西来为你做这件事。我怀疑性能不会成为问题,除非您要解析数百个url。

一个不用正则表达式的小技巧:

var tmp        = document.createElement ('a');
;   tmp.href   = "http://www.example.com/12xy45";


// tmp.hostname will now contain 'www.example.com'
// tmp.host will now contain hostname and port 'www.example.com:80'

将上述内容包装在如下函数中,您就拥有了从URI中获取域部分的绝佳方法。

function url_domain(data) {
var    a      = document.createElement('a');
a.href = data;
return a.hostname;
}
// use this if you know you have a subdomain
// www.domain.com -> domain.com
function getDomain() {
return window.location.hostname.replace(/([a-zA-Z0-9]+.)/,"");
}

我尝试使用给定的解决方案,选择的解决方案对我的目的来说是多余的,而“创建一个元素”对我来说是一团糟。

它还没有准备好在URL的端口。我希望有人觉得它有用

function parseURL(url){
parsed_url = {}


if ( url == null || url.length == 0 )
return parsed_url;


protocol_i = url.indexOf('://');
parsed_url.protocol = url.substr(0,protocol_i);


remaining_url = url.substr(protocol_i + 3, url.length);
domain_i = remaining_url.indexOf('/');
domain_i = domain_i == -1 ? remaining_url.length - 1 : domain_i;
parsed_url.domain = remaining_url.substr(0, domain_i);
parsed_url.path = domain_i == -1 || domain_i + 1 == remaining_url.length ? null : remaining_url.substr(domain_i + 1, remaining_url.length);


domain_parts = parsed_url.domain.split('.');
switch ( domain_parts.length ){
case 2:
parsed_url.subdomain = null;
parsed_url.host = domain_parts[0];
parsed_url.tld = domain_parts[1];
break;
case 3:
parsed_url.subdomain = domain_parts[0];
parsed_url.host = domain_parts[1];
parsed_url.tld = domain_parts[2];
break;
case 4:
parsed_url.subdomain = domain_parts[0];
parsed_url.host = domain_parts[1];
parsed_url.tld = domain_parts[2] + '.' + domain_parts[3];
break;
}


parsed_url.parent_domain = parsed_url.host + '.' + parsed_url.tld;


return parsed_url;
}

运行:

parseURL('https://www.facebook.com/100003379429021_356001651189146');

结果:

Object {
domain : "www.facebook.com",
host : "facebook",
path : "100003379429021_356001651189146",
protocol : "https",
subdomain : "www",
tld : "com"
}

我给你3个可能的解决方案:

  1. 使用npmpsl来提取你扔给它的任何东西。
  2. 使用我的自定义实现extractRootDomain,它适用于大多数情况。
  3. URL(url).hostname是有效的,但不是对所有的边缘情况。点击“运行片段”;看看它如何对抗他们。

1. 使用npm包psl(公共后缀列表)

“公共后缀列表”;是所有有效域名后缀和规则的列表,不仅仅是国家代码顶级域名,还有被认为是根域的unicode字符(例如www.食狮.公司.cn, b.c.a bebe .jp等)。阅读更多关于它在这里

试一试:

npm install --save psl

然后用我的“extracthostname”;实现运行:

let psl = require('psl');
let url = 'http://www.youtube.com/watch?v=ClkQA2Lb_iE';
psl.get(extractHostname(url)); // returns youtube.com

2. extractRootDomain的自定义实现

下面是我的实现,它还针对各种可能的URL输入运行。

function extractHostname(url) {
var hostname;
//find & remove protocol (http, ftp, etc.) and get hostname


if (url.indexOf("//") > -1) {
hostname = url.split('/')[2];
} else {
hostname = url.split('/')[0];
}


//find & remove port number
hostname = hostname.split(':')[0];
//find & remove "?"
hostname = hostname.split('?')[0];


return hostname;
}


// Warning: you can use this function to extract the "root" domain, but it will not be as accurate as using the psl package.


function extractRootDomain(url) {
var domain = extractHostname(url),
splitArr = domain.split('.'),
arrLen = splitArr.length;


//extracting the root domain here
//if there is a subdomain
if (arrLen > 2) {
domain = splitArr[arrLen - 2] + '.' + splitArr[arrLen - 1];
//check to see if it's using a Country Code Top Level Domain (ccTLD) (i.e. ".me.uk")
if (splitArr[arrLen - 2].length == 2 && splitArr[arrLen - 1].length == 2) {
//this is using a ccTLD
domain = splitArr[arrLen - 3] + '.' + domain;
}
}
return domain;
}


const urlHostname = url => {
try {
return new URL(url).hostname;
}
catch(e) { return e; }
};


const urls = [
"http://www.blog.classroom.me.uk/index.php",
"http://www.youtube.com/watch?v=ClkQA2Lb_iE",
"https://www.youtube.com/watch?v=ClkQA2Lb_iE",
"www.youtube.com/watch?v=ClkQA2Lb_iE",
"ftps://ftp.websitename.com/dir/file.txt",
"websitename.com:1234/dir/file.txt",
"ftps://websitename.com:1234/dir/file.txt",
"example.com?param=value",
"https://facebook.github.io/jest/",
"//youtube.com/watch?v=ClkQA2Lb_iE",
"www.食狮.公司.cn",
"b.c.kobe.jp",
"a.d.kyoto.or.jp",
"http://localhost:4200/watch?v=ClkQA2Lb_iE"
];


const test = (method, arr) => console.log(
`=== Testing "${method.name}" ===\n${arr.map(url => method(url)).join("\n")}\n`);


test(extractHostname, urls);
test(extractRootDomain, urls);
test(urlHostname, urls);

无论是否有协议或端口号,您都可以提取域。这是一个非常简化的,非正则表达式的解,所以我认为这可以解决我们在问题中提供的数据集。

3.URL(url).hostname

URL(url).hostname是一个有效的解决方案,但它不能很好地处理我已经解决的一些边缘情况。正如您在上次测试中看到的,它不喜欢某些url。你绝对可以使用我的解决方案的组合来让它全部工作。

*感谢@Timmerz, @renoirb, @rineez, @BigDong, @ra00l, @ILikeBeansTacos, @CharlesRobertson的建议!@ross-allen,谢谢你报告这个bug!

String.prototype.trim = function(){return his.replace(/^\s+|\s+$/g,"");}
function getHost(url){
if("undefined"==typeof(url)||null==url) return "";
url = url.trim(); if(""==url) return "";
var _host,_arr;
if(-1<url.indexOf("://")){
_arr = url.split('://');
if(-1<_arr[0].indexOf("/")||-1<_arr[0].indexOf(".")||-1<_arr[0].indexOf("\?")||-1<_arr[0].indexOf("\&")){
_arr[0] = _arr[0].trim();
if(0==_arr[0].indexOf("//")) _host = _arr[0].split("//")[1].split("/")[0].trim().split("\?")[0].split("\&")[0];
else return "";
}
else{
_arr[1] = _arr[1].trim();
_host = _arr[1].split("/")[0].trim().split("\?")[0].split("\&")[0];
}
}
else{
if(0==url.indexOf("//")) _host = url.split("//")[1].split("/")[0].trim().split("\?")[0].split("\&")[0];
else return "";
}
return _host;
}
function getHostname(url){
if("undefined"==typeof(url)||null==url) return "";
url = url.trim(); if(""==url) return "";
return getHost(url).split(':')[0];
}
function getDomain(url){
if("undefined"==typeof(url)||null==url) return "";
url = url.trim(); if(""==url) return "";
return getHostname(url).replace(/([a-zA-Z0-9]+.)/,"");
}
function hostname(url) {
var match = url.match(/:\/\/(www[0-9]?\.)?(.[^/:]+)/i);
if ( match != null && match.length > 2 && typeof match[2] === 'string' && match[2].length > 0 ) return match[2];
}

上面的代码将成功解析以下示例url的主机名:

http://WWW.first.com/folder/page.html first.com < / p >

http://mail.google.com/folder/page.html mail.google.com < / p >

https://mail.google.com/folder/page.html mail.google.com < / p >

http://www2.somewhere.com/folder/page.html?q=1 somewhere.com < / p >

https://www.another.eu/folder/page.html?q=1 another.eu < / p >

最初的贷方是:http://www.primaryobjects.com/CMS/Article145

如果你在这个页面结束,你正在寻找最好的正则表达式的url试试这个:

^(?:https?:)?(?:\/\/)?([^\/\?]+)

https://regex101.com/r/pX5dL9/1

你可以像下面这样使用它,也可以用不区分大小写的方式来匹配HTTPSHTTP:

const match = str.match(/^(?:https?:)?(?:\/\/)?([^\/\?]+)/i);
const hostname = match && match[1];

它适用于url没有http://,与http,与https,与只是//和不抓取路径和查询路径以及。

祝你好运

不需要解析字符串,只需将URL作为参数传递给URL构造函数:

const url = 'http://www.youtube.com/watch?v=ClkQA2Lb_iE';
const { hostname } = new URL(url);


console.assert(hostname === 'www.youtube.com');

尝试下面的代码为精确的域名使用正则表达式,

字符串line = "http://www.youtube.com/watch?v=ClkQA2Lb_iE";

  String pattern3="([\\w\\W]\\.)+(.*)?(\\.[\\w]+)";


Pattern r = Pattern.compile(pattern3);




Matcher m = r.matcher(line);
if (m.find( )) {


System.out.println("Found value: " + m.group(2) );
} else {
System.out.println("NO MATCH");
}

简单来说,你可以这样做

var url = "http://www.someurl.com/support/feature"


function getDomain(url){
domain=url.split("//")[1];
return domain.split("/")[0];
}
eg:
getDomain("http://www.example.com/page/1")


output:
"www.example.com"

使用上述函数获取域名

代码:

var regex = /\w+.(com|co\.kr|be)/ig;
var urls = ['http://www.youtube.com/watch?v=ClkQA2Lb_iE',
'http://youtu.be/ClkQA2Lb_iE',
'http://www.example.com/12xy45',
'http://example.com/random'];




$.each(urls, function(index, url) {
var convertedUrl = url.match(regex);
console.log(convertedUrl);
});

结果:

youtube.com
youtu.be
example.com
example.com

好吧,我知道这是一个老问题,但我做了一个超级高效的url解析器,所以我想我要分享它。

如你所见,这个函数的结构很奇怪,但这是为了提高效率。不使用原型函数,字符串迭代次数不超过一次,处理字符的次数也不超过必要的次数。

function getDomain(url) {
var dom = "", v, step = 0;
for(var i=0,l=url.length; i<l; i++) {
v = url[i]; if(step == 0) {
//First, skip 0 to 5 characters ending in ':' (ex: 'https://')
if(i > 5) { i=-1; step=1; } else if(v == ':') { i+=2; step=1; }
} else if(step == 1) {
//Skip 0 or 4 characters 'www.'
//(Note: Doesn't work with www.com, but that domain isn't claimed anyway.)
if(v == 'w' && url[i+1] == 'w' && url[i+2] == 'w' && url[i+3] == '.') i+=4;
dom+=url[i]; step=2;
} else if(step == 2) {
//Stop at subpages, queries, and hashes.
if(v == '/' || v == '?' || v == '#') break; dom += v;
}
}
return dom;
}

今天正在寻找解决这个问题的方法。上述答案似乎都不令人满意。我想要一个解决方案,可以是一行,没有条件逻辑,没有什么必须包装在一个函数。

这是我想到的,似乎真的很有效:

hostname="http://www.example.com:1234"
hostname.split("//").slice(-1)[0].split(":")[0].split('.').slice(-2).join('.')   // gives "example.com"

乍一看可能很复杂,但它的工作原理很简单;关键是在一些地方使用'slice(-n)',在这些地方,好的部分必须从分割数组的结束中取出(而[0]则从分割数组的前面取出)。

这些测试都返回"example.com":

"http://example.com".split("//").slice(-1)[0].split(":")[0].split('.').slice(-2).join('.')
"http://example.com:1234".split("//").slice(-1)[0].split(":")[0].split('.').slice(-2).join('.')
"http://www.example.com:1234".split("//").slice(-1)[0].split(":")[0].split('.').slice(-2).join('.')
"http://foo.www.example.com:1234".split("//").slice(-1)[0].split(":")[0].split('.').slice(-2).join('.')

下面是jQuery的一行代码:

$('<a>').attr('href', url).prop('hostname');

这不是一个完整的答案,但下面的代码应该会帮助你:

function myFunction() {
var str = "https://www.123rf.com/photo_10965738_lots-oop.html";
matches = str.split('/');
return matches[2];
}

我想有人比我更快地创建代码。它也有助于提高我自己。

所有url属性,没有依赖,没有JQuery,容易理解

这个解决方案给了你的答案和额外的性质。不需要JQuery或其他依赖,粘贴和走。

使用

getUrlParts("https://news.google.com/news/headlines/technology.html?ned=us&hl=en")

输出

{
"origin": "https://news.google.com",
"domain": "news.google.com",
"subdomain": "news",
"domainroot": "google.com",
"domainpath": "news.google.com/news/headlines",
"tld": ".com",
"path": "news/headlines/technology.html",
"query": "ned=us&hl=en",
"protocol": "https",
"port": 443,
"parts": [
"news",
"google",
"com"
],
"segments": [
"news",
"headlines",
"technology.html"
],
"params": [
{
"key": "ned",
"val": "us"
},
{
"key": "hl",
"val": "en"
}
]
}
< p > 代码
代码设计得很容易理解,而不是超级快。它可以很容易地每秒调用100次,所以它非常适合前端或少量服务器使用,但不适用于高容量吞吐量
function getUrlParts(fullyQualifiedUrl) {
var url = {},
tempProtocol
var a = document.createElement('a')
// if doesn't start with something like https:// it's not a url, but try to work around that
if (fullyQualifiedUrl.indexOf('://') == -1) {
tempProtocol = 'https://'
a.href = tempProtocol + fullyQualifiedUrl
} else
a.href = fullyQualifiedUrl
var parts = a.hostname.split('.')
url.origin = tempProtocol ? "" : a.origin
url.domain = a.hostname
url.subdomain = parts[0]
url.domainroot = ''
url.domainpath = ''
url.tld = '.' + parts[parts.length - 1]
url.path = a.pathname.substring(1)
url.query = a.search.substr(1)
url.protocol = tempProtocol ? "" : a.protocol.substr(0, a.protocol.length - 1)
url.port = tempProtocol ? "" : a.port ? a.port : a.protocol === 'http:' ? 80 : a.protocol === 'https:' ? 443 : a.port
url.parts = parts
url.segments = a.pathname === '/' ? [] : a.pathname.split('/').slice(1)
url.params = url.query === '' ? [] : url.query.split('&')
for (var j = 0; j < url.params.length; j++) {
var param = url.params[j];
var keyval = param.split('=')
url.params[j] = {
'key': keyval[0],
'val': keyval[1]
}
}
// domainroot
if (parts.length > 2) {
url.domainroot = parts[parts.length - 2] + '.' + parts[parts.length - 1];
// check for country code top level domain
if (parts[parts.length - 1].length == 2 && parts[parts.length - 1].length == 2)
url.domainroot = parts[parts.length - 3] + '.' + url.domainroot;
}
// domainpath (domain+path without filenames)
if (url.segments.length > 0) {
var lastSegment = url.segments[url.segments.length - 1]
var endsWithFile = lastSegment.indexOf('.') != -1
if (endsWithFile) {
var fileSegment = url.path.indexOf(lastSegment)
var pathNoFile = url.path.substr(0, fileSegment - 1)
url.domainpath = url.domain
if (pathNoFile)
url.domainpath = url.domainpath + '/' + pathNoFile
} else
url.domainpath = url.domain + '/' + url.path
} else
url.domainpath = url.domain
return url
}

我个人对这个解决方案做了很多研究,我能找到的最好的解决方案实际上来自CloudFlare的“浏览器检查”:

function getHostname(){
secretDiv = document.createElement('div');
secretDiv.innerHTML = "<a href='/'>x</a>";
secretDiv = secretDiv.firstChild.href;
var HasHTTPS = secretDiv.match(/https?:\/\//)[0];
secretDiv = secretDiv.substr(HasHTTPS.length);
secretDiv = secretDiv.substr(0, secretDiv.length - 1);
return(secretDiv);
}


getHostname();

我重写了变量,使它更“人类”可读,但它比预期的工作做得更好。

jquery Oneline

$('<a>').attr('href', document.location.href).prop('hostname');

好吧,使用正则表达式会容易得多:

    mainUrl = "http://www.mywebsite.com/mypath/to/folder";
urlParts = /^(?:\w+\:\/\/)?([^\/]+)(.*)$/.exec(mainUrl);
host = Fragment[1]; // www.mywebsite.com

有两个很好的解决方案,这取决于你是否需要优化性能(并且没有外部依赖!):

1. 使用URL.hostname提高可读性

最干净和最简单的解决方案是使用URL.hostname

const getHostname = (url) => {
// use URL constructor and return hostname
return new URL(url).hostname;
}


// tests
console.log(getHostname("https://stackoverflow.com/questions/8498592/extract-hostname-name-from-string/"));
console.log(getHostname("https://developer.mozilla.org/en-US/docs/Web/API/URL/hostname"));

URL.hostnameURL API的一部分,除IE (caniuse)之外的所有主流浏览器都支持。如果需要支持旧浏览器,请使用URL polyfill

额外的好处:使用URL构造函数还可以让你访问其他URL属性和方法!


2. 使用RegEx来提高性能

URL.hostname应该是大多数用例的选择。然而,它仍然比这个正则表达式(自己在jsPerf上测试)慢得多:

const getHostnameFromRegex = (url) => {
// run against regex
const matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
// extract hostname (will be null if no match is found)
return matches && matches[1];
}


// tests
console.log(getHostnameFromRegex("https://stackoverflow.com/questions/8498592/extract-hostname-name-from-string/"));
console.log(getHostnameFromRegex("https://developer.mozilla.org/en-US/docs/Web/API/URL/hostname"));


博士TL;

你可能应该使用URL.hostname。如果您需要处理大量的url(其中性能是一个因素),请考虑RegEx。

只需使用URL()构造函数:

new URL(url).host

parse-domain -一个非常可靠的轻量级库

npm install parse-domain

const { fromUrl, parseDomain } = require("parse-domain");

示例1

parseDomain(fromUrl("http://www.example.com/12xy45"))
{ type: 'LISTED',
hostname: 'www.example.com',
labels: [ 'www', 'example', 'com' ],
icann:
{ subDomains: [ 'www' ],
domain: 'example',
topLevelDomains: [ 'com' ] },
subDomains: [ 'www' ],
domain: 'example',
topLevelDomains: [ 'com' ] }

示例2

parseDomain(fromUrl("http://subsub.sub.test.ExAmPlE.coM/12xy45"))
{ type: 'LISTED',
hostname: 'subsub.sub.test.example.com',
labels: [ 'subsub', 'sub', 'test', 'example', 'com' ],
icann:
{ subDomains: [ 'subsub', 'sub', 'test' ],
domain: 'example',
topLevelDomains: [ 'com' ] },
subDomains: [ 'subsub', 'sub', 'test' ],
domain: 'example',
topLevelDomains: [ 'com' ] }

为什么?

根据用例和容量,我强烈建议不要自己使用正则表达式或其他字符串操作方法来解决这个问题。这个问题的核心是你需要知道所有的GTLD和CCTLD后缀来正确地将url字符串解析为域和子域,这些后缀会定期更新。这是一个已经解决的问题,而不是你想自己解决的问题(除非你是谷歌之类的)。除非你在紧要关头需要主机名或域名,否则不要试图通过解析来解决这个问题。

我的代码是这样的。 正则表达式可以有很多种形式,下面是我的测试用例

function extractUrlInfo(url){
let reg = /^((?<protocol>http[s]?):\/\/)?(?<host>((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])|[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)))(\:(?<port>[0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5]))?$/
return reg.exec(url).groups
}


var url = "https://192.168.1.1:1234"
console.log(extractUrlInfo(url))
var url = "https://stackoverflow.com/questions/8498592/extract-hostname-name-from-string"
console.log(extractUrlInfo(url))

import URL from 'url';


const pathname = URL.parse(url).path;
console.log(url.replace(pathname, ''));

这样就兼顾了协议。

这个解决方案工作得很好,如果URL包含大量无效字符,您也可以使用。

安装PSL包

npm install --save psl

实现

const psl = require('psl');


const url= new URL('http://www.youtube.com/watch?v=ClkQA2Lb_iE').hostname;
const parsed = psl.parse(url);

console.log(解析)

输出:

{
input: 'www.youtube.com',
tld: 'com',
sld: 'youtube',
domain: 'youtube.com',
subdomain: 'www',
listed: true
}