Расширенная группировка в регулярном выражении доменного имени с Python3 - PullRequest
0 голосов
/ 22 июня 2019

У меня есть программа, написанная на python3, которая должна анализировать несколько доменных имен каждый день и экстраполировать данные.
Анализируемые данные должны служить в качестве входных данных для функции поиска, для агрегирования (статистика и диаграммы) и сэкономить некоторое время для аналитика, который использует программу.

Точно так же, как вы знаете: у меня действительно нет времени изучать машинное обучение (что здесь кажется довольно хорошим решением), поэтому я решил начать с регулярного выражения, которое я уже использую.
Я уже искал документацию regex внутри и вне StackOverflow и работал над отладчиком на regex101, и я до сих пор не нашел способ сделать то, что мне нужно.
Редактировать (24/6/2019): Я упоминаю машинное обучение из-за причины, по которой мне нужен сложный синтаксический анализатор, который максимально автоматизирует вещи. Это было бы полезно для автоматического выбора, такого как черный список, белый список и т. Д.

Парсер должен учитывать несколько вещей:

  • максимальное количество 126 поддоменов плюс TLD
  • каждый поддомен не должен быть длиннее 64 символов
  • каждый поддомен может содержать только буквенно-цифровые символы, а символ -
  • каждый поддомен не должен начинаться или заканчиваться символом -
  • TLD не должен быть длиннее 64 символов
  • TLD не должен содержать только цифры

но я пойду немного глубже:

  • первая строка может (необязательно) содержать «тип использования», такой как cpanel., mail., webdisk., autodiscover. и т. Д. (Или, может быть, www.)
  • TLD может (необязательно) содержать частицу, такую ​​как .co, .gov, .edu и т. Д. (Например, .co.uk)
  • последняя часть TLD на самом деле не проверяется ни в одном списке ccTLD / gTLD, и я не думаю, что это будет в будущем

Я решил, что полезно решить эту проблему - это группа регулярных выражений для необязательного типа использования, по одному для каждого субдомена и одна для TLD (необязательная частица должна находиться внутри группы TLD)
С учетом этих правил я нашел решение:

^(?P<USAGE>autodiscover|correo|cpanel|ftp|mail|new|server|webdisk|webhost|webmail[\d]?|wiki|www[\d]?\.)?([a-z\d][a-z\d\-]{0,62}[a-z\d])?((\.[a-z\d][a-z\d\-]{0,62}[a-z\d]){0,124}?(?P<TLD>(\.co|\.com|\.edu|\.net|\.org|\.gov)?\.(?!\d+)[a-z\d]{1,64})$

Приведенное выше решение не возвращает ожидаемых результатов


Я привожу здесь пару примеров:

Пара строк для разбора

without.further.ado.lets.travel.the.forest.com  
www.without.further.ado.lets.travel.the.forest.gov.it  

Группы, которые я ожидаю найти

  • FullMatch without.further.ado.lets.travel.the.forest.com
    group2 without
    group3 further
    group4 ado
    group5 lets
    group6 travel
    group7 the
    1099 * группа 8 *forest
    groupTLD .com
  • FullMatch www.without.further.ado.lets.travel.the.forest.gov.it
    groupUSAGE www.
    group2 without
    group3 further
    group4 ado
    group5 lets
    group6 travel
    group7 the
    * 1140 группа-*forest
    groupTLD .gov.it

Группы, которые я нахожу

  • FullMatch without.further.ado.lets.travel.the.forest.com
    group2 without
    group3 .further.ado.lets.travel.the.forest
    group4 .forest
    groupTLD .com
  • FullMatch www.without.further.ado.lets.travel.the.forest.gov.it
    groupUSAGE www.
    group2 without
    group3 .further.ado.lets.travel.the.forest
    group4 .forest
    groupTLD .gov.it
    группа 6 .gov

Как видно из примеров, пара частиц обнаруживается дважды, и это не то поведение, которое я искал, так или иначе. Любая попытка изменить формулу приводит к непредвиденным результатам.
Есть идеи о том, как найти ожидаемые результаты?

Ответы [ 2 ]

1 голос
/ 24 июня 2019

Это простая, четко определенная задача.Здесь нет нечеткости, сложности, догадок, просто серия простых тестов, чтобы выяснить все в вашем контрольном списке.Я понятия не имею, как «машинное обучение» будет уместным или полезным.Даже регулярное выражение совершенно не нужно.

Я не реализовал все, что вы хотите проверить, но заполнить пропущенные биты несложно.

import string

double_tld = ['gov', 'edu', 'co', 'add_others_you_need']

# we'll use this instead of regex to check subdomain validity
valid_sd_characters = string.ascii_letters + string.digits + '-'
valid_trans = str.maketrans('', '', valid_sd_characters)

def is_invalid_sd(sd):
    return sd.translate(valid_trans) != ''

def check_hostname(hostname):
    subdomains = hostname.split('.')

    # each subdomain can contain only alphanumeric characters and
    # the - character
    invalid_parts = list(filter(is_invalid_sd, subdomains))
    # TODO react if there are any invalid parts

    # "the TLD can (optionally) contain a particle like
    # .co, .gov, .edu and so on (.co.uk for example)"
    if subdomains[-2] in double_tld:
        subdomains[-2] += '.' + subdomains[-1]
        subdomains = subdomains[:-1]

    # "a maximum number of 126 subdomains plus the TLD"
    # TODO check list length of subdomains

    # "each subdomain must not begin or end with the - character"
    # "the TLD must not be longer than 64 characters"
    # "the TLD must not contain only digits"
    # TODO write loop, check first and last characters, length, isnumeric

    # TODO return something
0 голосов
/ 24 июня 2019

Я не знаю, возможно ли получить результат точно так, как вы просили.Я думаю, что с одним шаблоном он не может отловить результаты в разных группах (group2, group3, ..).

Я нашел один способ получить почти ожидаемый результат, используя модуль regex .

match = regex.search(r'^(?:(?P<USAGE>autodiscover|correo|cpanel|ftp|mail|new|server|webdisk|webhost|webmail[\d]?|wiki|www[\d]?)\.)?(?:([a-z\d][a-z\d\-]{0,62}[a-z\d])\.){0,124}?(?P<TLD>(?:co|com|edu|net|org|gov)?\.(?!\d+)[a-z\d]{1,64})$', 'www.without.further.ado.lets.travel.the.forest.gov.it')

Вывод:

match.captures(0)
['www.without.further.ado.lets.travel.the.forest.gov.it']
match.captures[1] or match.captures('USAGE')
['www.']
match.captures(2)
['without', 'further', 'ado', 'lets', 'travel', 'the', 'forest']
match.captures(3) or match.captures('TLD')
['gov.it']

Здесь, чтобы избежать взятия . в группах, я добавил его в группу без захвата, подобную этой

(?:([a-z\d][a-z\d\-]{0,62}[a-z\d])\.)

Надеюсь, это поможет.

...