Необходимо перейти от имени хоста к базовому домену

Мне нужна функция:

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'

Проще говоря, если suffix состоит из n сегментов, возьмите последние n+1 сегментов. Найдите базовый домен для полного доменного имени, учитывая тот факт, что некоторые полные доменные имена имеют более одного элемента суффикса.

Суффиксы, которые мне нужно сопоставить, находятся здесь. Они уже есть в моей базе данных SQL.

Я мог бы написать это на С#; это может быть не самым элегантным, но это сработает. К сожалению, я хотел бы иметь эту функцию либо в T-SQL, где она ближе всего к данным, либо в Powershell, где будет находиться остальная часть утилиты, потребляющей эти данные. Я полагаю, что было бы нормально сделать это на C #, скомпилировать в сборку, а затем получить к ней доступ из T-SQL или даже из Powershell ... если это будет самым быстрым выполнением. Если есть какая-то разумная альтернатива на чистом T-SQL или простом Powershell, мне бы это понравилось.

РЕДАКТИРОВАТЬ: Одна вещь, которую я забыл упомянуть явно (но это ясно при просмотре списка суффиксов по моей ссылке выше), заключается в том, что мы должны выбрать самый длинный совпадающий суффикс. И «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

Это работает нормально для поиска правильного суффикса. Хотя меня немного беспокоит его производительность.


person Ross Presser    schedule 19.12.2016    source источник
comment
Я предполагаю, что вы будете использовать манипуляции со строками .NET в C # для выполнения задачи, верно? если это так, вы можете просто делать то же самое в powershell (обработка строк такая же, и все методы, доступные в C #, также доступны в Powershell)   -  person Mike Garuccio    schedule 19.12.2016
comment
@TessellationHeckler вау. Это мощное краткое решение для регулярных выражений. К сожалению, это не защищает от чего-то вроде foo.bar.com.br.something.com.br или даже чего-то вроде my.computers.com.   -  person Ross Presser    schedule 19.12.2016
comment
Вместо того, чтобы полагаться на регулярные выражения и манипуляции со строками, я думаю, что для этого есть лучшие методы. stackoverflow.com/questions/10735190/ Это должен легко переводиться в PowerShell с помощью [system.uri]   -  person Matt    schedule 19.12.2016
comment
Также связано: host-domain-from-url   -  person Matt    schedule 19.12.2016
comment
Черт, я должен был закрепить его сильнее; $fqdn -replace "^.*?(?=[^.]+\.$suffix`$)" является доказательством против foo.bar.com.br.something.com.br ...   -  person TessellatingHeckler    schedule 19.12.2016
comment
@Matt: Принятый ответ на вопрос, который вы связали, НЕ делает ничего для получения базового домена.   -  person Ross Presser    schedule 21.12.2016
comment
@RossPresser Моя ошибка. Я думал, что класс URI поможет с разбором. Я подумал, что для этого должно быть что-то большее, чем синтаксический анализ строк.   -  person Matt    schedule 21.12.2016


Ответы (3)


Ниже показано сопоставление полных доменных имен с 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;
person HABO    schedule 19.12.2016
comment
Это хорошо, но требует уточнения, о котором я не упомянул явно в вопросе (но это неявно, если вы посмотрите на ссылку списка суффиксов). И br, и com.br появляются в списке суффиксов; предпочтение должно отдаваться самому длинному суффиксу. Я добавлю это к моему вопросу. - person Ross Presser; 20.12.2016
comment
Это работает очень хорошо в сочетании с методом левое самосоединение для поиска самого длинного совпадающего суффикса. Если вы обновите свой ответ на это, я приму его. - person Ross Presser; 20.12.2016
comment
@RossPresser Ответ был обновлен: (1) исправлена ​​дата выборки, (б) исправлена ​​обработка случая FQDN = TLD, (iii) добавлен пример, который выбирает наилучшее, то есть самое длинное TLD, совпадение для каждого FQDN. - person HABO; 20.12.2016

Вот как бы я сделал это на С#:

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

Сейчас кажется довольно глупым тратить на это время stackoverflow.com. Мои извинения.

person Ross Presser    schedule 19.12.2016
comment
Взгляните на ответы и комментарии, вам не нужно извиняться за это :) - person sodawillow; 20.12.2016

Вот вариант 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
person scsimon    schedule 19.12.2016