从字符串中提取主机名

IT技术 javascript jquery regex
2021-01-24 23:26:52

我只想匹配 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.comorexample.com域。

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

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

6个回答

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

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;
}
如果您需要快速完成,请不要使用它它比gilly3的方法慢约40-60倍。在 jsperf 中测试:jsperf.com/hostname-from-url
2021-04-05 23:26:52

我推荐使用 npm 包psl (Public Suffix List)“公共后缀列表”是所有有效域名后缀和规则的列表,不仅是国家代码顶级域名,还有被视为根域名的unicode字符(即www.食狮.公司.cn,bckobe .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

我不能使用 npm 包,所以下面只测试extractHostname。

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;
}

//test the code
console.log("== Testing extractHostname: ==");
console.log(extractHostname("http://www.blog.classroom.me.uk/index.php"));
console.log(extractHostname("http://www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("https://www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("ftps://ftp.websitename.com/dir/file.txt"));
console.log(extractHostname("websitename.com:1234/dir/file.txt"));
console.log(extractHostname("ftps://websitename.com:1234/dir/file.txt"));
console.log(extractHostname("example.com?param=value"));
console.log(extractHostname("https://facebook.github.io/jest/"));
console.log(extractHostname("//youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractHostname("http://localhost:4200/watch?v=ClkQA2Lb_iE"));

// 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;
}

//test extractRootDomain
console.log("== Testing extractRootDomain: ==");
console.log(extractRootDomain("http://www.blog.classroom.me.uk/index.php"));
console.log(extractRootDomain("http://www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractRootDomain("https://www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractRootDomain("www.youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractRootDomain("ftps://ftp.websitename.com/dir/file.txt"));
console.log(extractRootDomain("websitename.co.uk:1234/dir/file.txt"));
console.log(extractRootDomain("ftps://websitename.com:1234/dir/file.txt"));
console.log(extractRootDomain("example.com?param=value"));
console.log(extractRootDomain("https://facebook.github.io/jest/"));
console.log(extractRootDomain("//youtube.com/watch?v=ClkQA2Lb_iE"));
console.log(extractRootDomain("http://localhost:4200/watch?v=ClkQA2Lb_iE"));

无论有协议甚至端口号,您都可以提取域。这是一个非常简化的非正则表达式解决方案,所以我认为这样做可以。

*感谢@Timmerz、@renoirb、@rineez、@BigDong、@ra00l、@ILikeBeansTacos、@CharlesRobertson 的建议!@ross-allen,感谢您报告错误!

无需解析字符串,只需将您的 URL 作为参数传递给URL构造函数

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

console.assert(hostname === 'www.youtube.com');
2021 年及以后,这应该被接受吗?
2021-03-11 23:26:52

试试这个:

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

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

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。