从foo.bar.car.com的URL中获取特定的子域名

18

给定以下URL:

foo.bar.car.com.au

我需要提取foo.bar

我遇到了以下代码:

private static string GetSubDomain(Uri url)
{
    if (url.HostNameType == UriHostNameType.Dns)
    {
        string host = url.Host;
        if (host.Split('.').Length > 2)
        {
            int lastIndex = host.LastIndexOf(".");
            int index = host.LastIndexOf(".", lastIndex - 1);
            return host.Substring(0, index);
        }
    }         
    return null;     
}

这给了我像 foo.bar.car 这样的东西。我想要的是 foo.bar。我应该只使用 split 并取 0 和 1 吗?

但是可能会有 wwww。

有没有简单的方法可以做到这一点?


1
首先,让我们保持语言的干净整洁。但是,忘记代码,你如何知道 foo.barfoo.bar.car.com.au 中的子域名? - Mike Perrenoud
抱歉,这可能是美国的一种说法。我知道这是因为我正在开发它。 - DarthVader
问题不在于你,@DarthVader,如何知道。问题是,代码可以假设什么?请看下面的答案。 - Mark Reed
7个回答

18

考虑到您的需求(想要前两个级别,不包括“www.”),我会像这样处理:

private static string GetSubDomain(Uri url)
{

    if (url.HostNameType == UriHostNameType.Dns)
    {

        string host = url.Host;

        var nodes = host.Split('.');
        int startNode = 0;
        if(nodes[0] == "www") startNode = 1;

        return string.Format("{0}.{1}", nodes[startNode], nodes[startNode + 1]);

    }

    return null; 
}

9

我遇到了类似的问题,基于之前的答案,我写了这个扩展方法。最重要的是,它需要一个参数来定义“根”域名,即使用该方法的人认为的根域名。在OP的情况下,调用将会是:

Uri uri = "foo.bar.car.com.au";
uri.DnsSafeHost.GetSubdomain("car.com.au"); // returns foo.bar
uri.DnsSafeHost.GetSubdomain(); // returns foo.bar.car

以下是扩展方法:

/// <summary>Gets the subdomain portion of a url, given a known "root" domain</summary>
public static string GetSubdomain(this string url, string domain = null)
{
  var subdomain = url;
  if(subdomain != null)
  {
    if(domain == null)
    {
      // Since we were not provided with a known domain, assume that second-to-last period divides the subdomain from the domain.
      var nodes = url.Split('.');
      var lastNodeIndex = nodes.Length - 1;
      if(lastNodeIndex > 0)
        domain = nodes[lastNodeIndex-1] + "." + nodes[lastNodeIndex];
    }

    // Verify that what we think is the domain is truly the ending of the hostname... otherwise we're hooped.
    if (!subdomain.EndsWith(domain))
      throw new ArgumentException("Site was not loaded from the expected domain");

    // Quash the domain portion, which should leave us with the subdomain and a trailing dot IF there is a subdomain.
    subdomain = subdomain.Replace(domain, "");
    // Check if we have anything left.  If we don't, there was no subdomain, the request was directly to the root domain:
    if (string.IsNullOrWhiteSpace(subdomain))
      return null;

    // Quash any trailing periods
    subdomain = subdomain.TrimEnd(new[] {'.'});
  }

  return subdomain;
}

1
如果你要费心编写一个扩展方法,为什么不扩展System.Uri而不是字符串?这样它就有了适当的“URL”相关上下文。 - iCollect.it Ltd
@TrueBlueAussie 没错。我只是为了我的代码库开发MVP扩展了字符串。随着您所建议的未来重构,很可能会扩展System.Uri以保持上下文。 - HeyZiko

8
您可以使用以下的Nuget包Nager.PublicSuffix。它使用Mozilla的PUBLIC SUFFIX LIST来拆分域名。
PM> Install-Package Nager.PublicSuffix

示例

 var domainParser = new DomainParser();
 var data = await domainParser.LoadDataAsync();
 var tldRules = domainParser.ParseRules(data);
 domainParser.AddRules(tldRules);

 var domainName = domainParser.Get("sub.test.co.uk");
 //domainName.Domain = "test";
 //domainName.Hostname = "sub.test.co.uk";
 //domainName.RegistrableDomain = "test.co.uk";
 //domainName.SubDomain = "sub";
 //domainName.TLD = "co.uk";

2
这种方式是将域名/主机名分解为其各个部分的唯一方法,真是太荒谬了 - 需要完整的所有顶级域名列表,然后再拆分剩余部分。 - Martin Kirk

3
private static string GetSubDomain(Uri url)
{
    if (url.HostNameType == UriHostNameType.Dns)
    {

        string host = url.Host;   
        String[] subDomains = host.Split('.');
        return subDomains[0] + "." + subDomains[1];
     }
    return null; 
}

3

首先,您是要寻找“com.au”域名,还是一般的互联网域名?因为如果是后者,没有简单的自动方式可以确定域名中有多少部分是“站点”或“区域”等,有多少部分是该区域内的单个“主机”或其他记录。

如果您需要能够从任意域名中找出这些信息,则需要从Mozilla Public Suffix项目(http://publicsuffix.org)获取TLD列表,并使用它们的算法来查找域名中的TLD。然后,您可以假定您想要的部分以TLD之前的最后一个标签结尾。


从“健壮代码”的角度来看,这比我的答案正确得多。如果您知道您始终只想要前两个级别,那么我的答案可以工作(作为起点),但总体而言,这更好。 - AllenG

2
我建议使用正则表达式。以下代码片段应该可以提取您要查找的内容...
string input = "foo.bar.car.com.au";
var match = Regex.Match(input, @"^\w*\.\w*\.\w*");
var output = match.Value;

using System.Text.RegularExpressions; - Nikas music and gaming

1
除了在此答案中指定的NuGet Nager.PubilcSuffix包外,还有NuGet Louw.PublicSuffix包,根据其GitHub项目页面,它是一个解析公共后缀的.Net Core库,并基于Nager.PublicSuffix项目,具有以下更改:
  • 移植到 .NET Core 库。
  • 修复库以通过所有综合测试。
  • 重构类以将功能拆分为更小的专注类。
  • 使类不可变。因此 DomainParser 可用作单例且线程安全。
  • 添加 WebTldRuleProviderFileTldRuleProvider
  • 添加了判断规则是 ICANN 还是私有域名规则的功能。
  • 使用异步编程模型。

该页面还指出,上述许多更改已提交回原始的 Nager.PublicSuffix 项目


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接