【问题标题】:Need to go from hostname to base domain需要从主机名转到基域
【发布时间】:2017-05-04 20:57:46
【问题描述】:

我需要一个函数:

f(fqdn,suffix) -> basedomain

使用这些示例输入和输出:

f('foobar.quux.somedomain.com','com') -> 'somedomain.com'
f('somedomain.com','com') -> 'somedomain.com'
f('foobar.quux.somedomain.com.br','com.br') -> 'somedomain.com.br'
f('somedomain.com.br','com.br') -> 'somedomain.com.br'

用简单的英语,如果suffixn 段,则取最后一个n+1 段。找到 FQDN 的基域,考虑到某些 FQDN 有多个后缀元素这一事实。

我需要匹配的后缀是here。我已经在我的 SQL 数据库中获得了它们。

我可以用 C# 写这个;它可能不是最优雅的,但它会起作用。不幸的是,我希望在最接近数据的 T-SQL 或 Powershell 中使用此功能,这是使用此数据的其余实用程序将在其中使用的地方。我想可以在 C# 中执行此操作,编译为程序集,然后从 T-SQL 甚至从 Powershell 访问它……如果这将是最快的执行。如果在纯 T-SQL 或简单的 Powershell 中有一些相当聪明的替代方案,我会喜欢的。

编辑:我忘记明确提及的一件事(但在查看后缀列表时很清楚,在我上面的链接中)是我们必须选择 longest 匹配的后缀。 “br”和“com.br”都出现在后缀列表中(类似的事情发生在 uk、pt 等)。所以 SQL 必须使用窗口函数来确保找到最长的匹配后缀。

这是我在执行 SQL 时的进度。我迷失在所有substring/reverse 函数中。

SELECT Domain, suffix
FROM (
    SELECT SD.Domain, SL.suffix, 
       RN=ROW_NUMBER() OVER (
           PARTITION BY sd.Domain ORDER BY LEN(SL.suffix) DESC)
    FROM SiteDomains SD
    INNER JOIN suffixlist SL ON SD.Domain LIKE '%.'+SL.suffix
) AS X
WHERE RN=1

这适用于找到正确的后缀。不过我有点担心它的性能。

【问题讨论】:

  • 我假设您会在 C# 中使用 .NET 字符串操作来完成任务,对吧?如果是这样,您可以在 powershell 中执行完全相同的操作(字符串处理是相同的,并且 C# 中可用的所有方法在 Powershell 中也可用)
  • $fqdn -replace ".*?(?=[^.]+\.$suffix)"
  • @TessellatingHeckler 。这是一个非常简短的正则表达式解决方案。不幸的是,它不能证明像 foo.bar.com.br.something.com.br 甚至像 my.computers.com 这样的东西
  • 我认为有更好的方法,而不是依赖正则表达式和字符串操作。 *.com/questions/10735190/… 这应该很容易转换为 PowerShell 以及 [system.uri]

标签: tsql powershell fqdn


【解决方案1】:

以下演示了将 FQDN 与 TLD 匹配并提取所需的 n + 1 个域名段:

-- Sample data.
declare @SampleTLDs as Table ( TLD VarChar(64) );
insert into @SampleTLDs ( TLD ) values
  ( 'com' ), ( 'somedomain.com' ), ( 'com.br' );
declare @SampleFQDNs as Table ( FQDN VarChar(64) );
insert into @SampleFQDNs ( FQDN ) values
  ( 'foobar.quux.somedomain.com' ), ( 'somedomain.com' ),
  ( 'foobar.quux.somedomain.com.br' ), ( 'somedomain.com.br' );
select * from @SampleTLDs;
select * from @SampleFQDNs;

-- Fiddle about.
select FQDN, TLD,
  case
    when DotPosition = 0 then FQDN
    else Reverse( Left( ReversedPrefix, DotPosition - 1) ) + '.' + TLD
    end as Result
  from (
    select FQDNs.FQDN, TLDs.TLD,
      Substring( Reverse( FQDNs.FQDN ), Len( TLDs.TLD ) + 2, 100 ) as ReversedPrefix,
      CharIndex( '.', Substring( Reverse( FQDNs.FQDN ), Len( TLDs.TLD ) + 2, 100 ) ) as DotPosition
      from @SampleFQDNs as FQDNs inner join
        @SampleTLDs as TLDs on FQDNs.FQDN like '%.' + TLDs.TLD or FQDNs.FQDN = TLDs.TLD  ) as Edna;

-- To select only the longest matching TLD for each FQDN:
with
  ExtendedFQDNs as (
    select FQDNs.FQDN, TLDs.TLD, Row_Number() over ( partition by FQDN order by Len( TLDs.TLD ) desc ) as TLDLenRank,
      Substring( Reverse( FQDNs.FQDN ), Len( TLDs.TLD ) + 2, 100 ) as ReversedPrefix,
      CharIndex( '.', Substring( Reverse( FQDNs.FQDN ), Len( TLDs.TLD ) + 2, 100 ) ) as DotPosition
      from @SampleFQDNs as FQDNs inner join
        @SampleTLDs as TLDs on FQDNs.FQDN like '%.' + TLDs.TLD or FQDNs.FQDN = TLDs.TLD )
  select FQDN, TLD,
    case
      when DotPosition = 0 then FQDN
      else Reverse( Left( ReversedPrefix, DotPosition - 1) ) + '.' + TLD
      end as Result
    from ExtendedFQDNs
    where TLDLenRank = 1;

【讨论】:

  • 这很好,但需要改进,我没有在问题中明确提及(但如果你查看后缀列表链接,它是隐含的)。 “br”和“com.br”都出现在后缀列表中;必须首选最长的后缀。我会将此添加到我的问题中。
  • 这在与left self join 查找最长匹配后缀的技术配合使用时效果非常好。如果您为此更新答案,我会接受。
  • @RossPresser 答案已更新:(1) 更正了样​​本日期,(b) 更正了 FQDN = TLD 案例的处理,(iii) 添加了选择“最佳”的示例,即最长的 TLD , 匹配每个 FQDN。
【解决方案2】:

这是一个 tsql 变体...

declare @fqdn varchar(256) = 'somedomain.com'
declare @suffix varchar(128) = 'com'

select left(@fqdn,CHARINDEX(@suffix,@fqdn) - 2)

if(select CHARINDEX('.',reverse(left(@fqdn,CHARINDEX(@suffix,@fqdn) - 2)))) = 0
    begin
    select left(@fqdn,CHARINDEX(@suffix,@fqdn) - 2) + '.' + @suffix
    end
else
    begin
    select right(left(@fqdn,CHARINDEX(@suffix,@fqdn) - 2),CHARINDEX('.',reverse(left(@fqdn,CHARINDEX(@suffix,@fqdn) - 2))) - 1) + '.' + @suffix
    end

【讨论】:

    【解决方案3】:

    这是我在 C# 中的做法:

    string getBaseDomain(string fqdn, string suffix)
    {
        string[] domainSegs = fqdn.Split('.');
        return domainSegs[domainSegs.Length - suffix.Split('.').Length - 1] + "." + suffix;
    }
    

    所以它在 Powershell 中:

    function getBaseDomain
    {
      Param(
        [string]$fqdn, 
        [string]$suffix 
      )
      $domainSegs = $fqdn.Split(".");
      return $domainSegs[$domainSegs.Length - $suffix.Split(".").Length - 1] + "."+$suffix;
    }
    

    现在浪费 *.com 的时间似乎很愚蠢。我很抱歉。

    【讨论】:

    • 看看答案和cmets,你不需要为此道歉:)