从字符串中提取主机名

Cha*_*yan 211 javascript regex jquery

我想只匹配URL的根,而不是文本字符串中的整个URL.鉴于:

http://www.youtube.com/watch?v=ClkQA2Lb_iE
http://youtu.be/ClkQA2Lb_iE
http://www.example.com/12xy45
http://example.com/random
Run Code Online (Sandbox Code Playgroud)

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

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

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

Fil*_*efp 286

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

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'
Run Code Online (Sandbox Code Playgroud)

将上面的内容包含在如下所示的函数中,您可以通过一种极好的方式从URI中抢夺域名部分.

function url_domain(data) {
  var    a      = document.createElement('a');
         a.href = data;
  return a.hostname;
}
Run Code Online (Sandbox Code Playgroud)

  • **如果你需要快速**,请不要使用它.它比gilly3的方法慢大约40-60倍.在jsperf中测试过:http://jsperf.com/hostname-from-url. (43认同)
  • @Chamilyan我认为你应该接受这个答案..它更酷,没有任何额外的工作:) (9认同)
  • 实际上,我将尝试使用parseUri解决方案,但为创造力+1. (6认同)
  • 优秀解决方案 +1应该是接受的答案. (3认同)
  • 只是fyi - 这个解决方案不处理端口号 (3认同)

lew*_*dev 257

我建议使用npm包psl(Public Suffix List)."公共后缀列表"是所有有效域名后缀和规则的列表,不仅包括国家/地区代码顶级域名,还包括将被视为根域的unicode字符(即www.食狮.公司.cn,bckobe) .jp等).在这里阅读更多相关信息.

尝试:

npm install --save psl
Run Code Online (Sandbox Code Playgroud)

然后用我的"extractHostname"实现运行:

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

我不能使用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"));
Run Code Online (Sandbox Code Playgroud)

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

*感谢@Timmerz,@ renoirb,@ irineez,@ BigDong,@ ra00l,@ ilikeBeansTacos,@ CharlesRobertson提出的建议!@ ross-allen,感谢您报告错误!

  • 一个:http://www.youtube.com/watch - > www.youtube.com是youtube.com域名的www子域名.为了删除额外的www,我添加了:`if(domain.split('.').length> 2){//还有子域var splitArr = domain.split('.'); domain = splitArr [splitArr.length - 2] +'.' + splitArr [splitArr.length - 1]; }` (6认同)
  • 最好还支持任何协议符号长度.改进可能是`url.split('/')[2]`因为不管我们写`ftp`,`ftps`,`https`,域名总是在索引2. (3认同)
  • 2019 人,你可以简单地使用 [`URL.hostname`](https://developer.mozilla.org/en-US/docs/Web/API/URL/hostname) 并避免额外的依赖。请参阅[我在下面的回答](/sf/answers/3846343021/) :) (3认同)
  • 121KB gzip 压缩 https://bundlephobia.com/package/psl@1.8.0。这比 React 重 17 倍多。除非你有充分的理由不使用“URL().hostname”,否则这是一个非常糟糕的解决方案,而且可能是最慢的解决方案(因为它的包大小) (3认同)

gil*_*ly3 120

试试这个:

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

如果要从结果中排除端口,请改用以下表达式:

/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i
Run Code Online (Sandbox Code Playgroud)

编辑:要防止特定域匹配,请使用否定前瞻.(?!youtube.com)

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

  • @FellowStranger - 将`(?:www \.)?`添加到正则表达式中:`/^https?\:\/\/(?:www..)?([^\/?#]+) (?:[?\ /#] | $)/ i` (7认同)
  • 不要忘记protocol:// username:password @ host:port/path/to/resource等格式... (3认同)
  • +1,因为它非常快,这在我的情况下是一个要求 (3认同)
  • 您可能希望在否定前瞻中添加一个可选的`(?:www \.)?`. (2认同)

Pav*_*vlo 107

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

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

assert(hostname === 'www.youtube.com');
Run Code Online (Sandbox Code Playgroud)

  • 2021 年及以后,这个答案应该被接受吗? (9认同)
  • 与@mc下面的答案相同.另外看看评论"新的URL()不适用于IE(测试IE11)". (6认同)
  • +1 这应该是公认的答案。它快速、可靠,适用于所有现代浏览器,不依赖于外部库并且易于理解(与正则表达式解决方案相反)。我还认为它非常快,因为它是每个浏览器的核心功能(虽然它通常并不重要)。 (3认同)
  • 尽管如此,它可能是最容易使用的解决方案,所以+1 (2认同)
  • 我在 chrome 扩展中使用它,所以目前没有 IE 支持对我来说很好。 (2认同)

And*_*ite 36

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

  • **如果你需要快速**,请不要使用它.只是获取主机名,它比gilly3的方法慢大约40-60倍.在jsperf中测试过:http://jsperf.com/hostname-from-url. (12认同)
  • `new URL()`不适用于IE(测试IE11) (11认同)
  • 不幸的是,IE10不支持URL. (2认同)

Rob*_*ral 16

使用URL.hostname的可读性

在Babel时代,最干净,最简单的解决方案是使用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"));
Run Code Online (Sandbox Code Playgroud)

URL.hostnameURL API的一部分,除IE(caniuse)之外,所有主流浏览器均支持:

使用此解决方案还将使您能够访问其他URL属性和方法。例如,如果您还想提取URL的路径名查询字符串参数,这将很有用。


使用RegEx提高性能

URL.hostname比使用锚点解决方案parseUri更快。但是它仍然比gilly3的regex慢很多:

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"));
Run Code Online (Sandbox Code Playgroud)

在此jsPerf上自己测试

如果您需要处理大量URL(性能是一个重要因素),我建议改用此解决方案。否则,选择URL.hostname可读性。

  • 这些应该是公认的答案。 (3认同)

Lui*_*pes 13

如果你最终在这个页面上,并且你正在寻找URL的最佳REGEX尝试这个:

^(?:https?:)?(?:\/\/)?([^\/\?]+)
Run Code Online (Sandbox Code Playgroud)

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

它适用于没有http://的网址,带有http,带有https,只有//并且也不会抓取路径和查询路径.

祝好运


Bla*_*ine 12

我尝试使用Given解决方案,选择的解决方案对我的目的来说是一种过度杀伤,而"创造一个元素"对我来说是一个很糟糕的问题.

它还没有为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;
}
Run Code Online (Sandbox Code Playgroud)

运行这个:

parseURL('https://www.facebook.com/100003379429021_356001651189146');
Run Code Online (Sandbox Code Playgroud)

结果:

Object {
    domain : "www.facebook.com",
    host : "facebook",
    path : "100003379429021_356001651189146",
    protocol : "https",
    subdomain : "www",
    tld : "com"
}
Run Code Online (Sandbox Code Playgroud)


whi*_*and 8

所有url属性,无依赖,无JQuery,简单易懂

此解决方案提供您的答案以及其他属性。不需要 JQuery 或其他依赖项,粘贴即可。

用法

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

输出

{
  "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"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

代码
代码旨在易于理解而不是超快。它每秒可以轻松调用 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
}
Run Code Online (Sandbox Code Playgroud)

  • @Lee 输入失败:`var url="https://mail.gggg.google.cn/link/link/link";` domainroot 应该是 `google.com` 但它输出:`gggg. google.cn` 而`gggg` 是一个子域(域可以有多个子域)。 (2认同)

jag*_*oft 5

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];
}
Run Code Online (Sandbox Code Playgroud)

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

http://WWW.first.com/folder/page.htmlfirst.com

http://mail.google.com/folder/page.html mail.google.com

https://mail.google.com/folder/page.html mail.google.com

http://www2.somewhere.com/folder/page.html?q=1 Something.com

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

原始信用转到:http://www.primaryobjects.com/CMS/Article145


zap*_*odb 5

今天正在寻找这个问题的解决方案。以上答案似乎都不令人满意。我想要一个解决方案,它可以是单行代码,没有条件逻辑,也不需要任何东西必须包含在函数中。

这是我想出的,似乎工作得很好:

主机名="http://www.example.com:1234"
hostname.split("//").slice(-1)[0].split(":")[0].split('.').slice(-2).join('.') //给出“example.com”

乍一看可能看起来很复杂,但它的工作原理很简单;关键是在几个地方使用 'slice(-n)' ,其中好的部分必须从拆分数组的末尾拉出(和 [0] 从拆分数组的前面获取)。

这些测试中的每一个都返回“example.com”:

"http://example.com".split("//").slice(-1)[0].split(":")[0].split('.').slice(-2)。加入('。')
"http://example.com:1234".split("//").slice(-1)[0].split(":")[0].split('.').slice(-2 )。加入('。')
"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('.')


gra*_*vic 5

这是 jQuery 单行代码:

$('<a>').attr('href', url).prop('hostname');
Run Code Online (Sandbox Code Playgroud)


小智 5

这不是完整的答案,但下面的代码应该可以帮助您:

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

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