【问题标题】:Get specific subdomain from URL in foo.bar.car.com从 foo.bar.car.com 中的 URL 获取特定子域
【发布时间】:2013-11-13 03:02:10
【问题描述】:

给定一个 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。

有没有简单的方法?

【问题讨论】:

  • 首先,让我们保持语言干净。但第二,忘记代码,你怎么知道 foo.barfoo.bar.car.com.au 中的子域?
  • 对语言感到抱歉。应该是美国的东西。我知道,因为我正在开发它。
  • 问题不在于你怎么知道,@DarthVader。问题是,代码可以假设什么?请参阅下面的答案..

标签: c# url


【解决方案1】:

鉴于您的要求(您想要第一个两个级别,不包括“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; 
}

【讨论】:

    【解决方案2】:

    我遇到了类似的问题,根据前面的答案,写了这个扩展方法。最重要的是,它需要一个定义“根”域的参数,即方法的使用者认为是根的任何参数。在 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;
    }
    

    【讨论】:

    • 如果你要编写扩展方法的麻烦,为什么不扩展System.Uri而不是字符串呢?然后它有一个适当的“URL”相关上下文。
    • @TrueBlueAussie 确实如此。我扩展字符串只是因为这是我的代码库的 MVP。正如您所建议的,未来的重构可能会导致扩展 System.Uri 以维护上下文。
    【解决方案3】:

    您可以使用以下 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";
    

    【讨论】:

    • 这是将域/主机名分解为各个部分的唯一方法,这非常荒谬 - 拥有所有 TLD 的完整列表,然后拆分其余部分。
    【解决方案4】:
    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; 
    }
    

    【讨论】:

      【解决方案5】:

      好的,首先。您是专门查看“com.au”,还是这些通用互联网域名?因为如果是后者,则根本没有自动方法来确定域中有多少是“站点”或“区域”或其他任何内容,以及该区域内的单个“主机”或其他记录有多少。

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

      【讨论】:

      • 从“健壮代码”的角度来看,这比我的回答要正确得多。如果你知道你总是只想要前两个级别,我的会工作(作为一个起点),但总的来说这更好。
      【解决方案6】:

      我建议使用正则表达式。以下代码 sn-p 应该提取您要查找的内容...

      string input = "foo.bar.car.com.au";
      var match = Regex.Match(input, @"^\w*\.\w*\.\w*");
      var output = match.Value;
      

      【讨论】:

      • using System.Text.RegularExpressions;
      【解决方案7】:

      除了this answer中指定的NuGetNager.PubilcSuffix包外,还有NuGetLouw.PublicSuffix包,根据其GitHub project page是一个解析Public Suffix的.Net Core库,基于在Nager.PublicSuffix project 上,进行了以下更改:

      • 移植到 .NET Core 库。
      • 修复了库,使其通过了所有综合测试。
      • 重构类以将功能拆分为更小的重点类。
      • 使类不可变。因此DomainParser 可以用作单例并且是线程安全的。
      • 添加了WebTldRuleProviderFileTldRuleProvider
      • 添加了了解规则是 ICANN 还是私有域规则的功能。
      • 使用异步编程模型

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

      【讨论】:

        猜你喜欢
        • 2010-09-22
        • 2011-03-13
        • 2022-11-30
        • 2021-03-22
        • 2011-10-19
        • 1970-01-01
        • 2012-03-25
        • 2018-02-15
        • 1970-01-01
        相关资源
        最近更新 更多