Как я могу позволить нечеткое совпадение с регулярным выражением только для части шаблона? - PullRequest
2 голосов
/ 16 марта 2019

У меня есть pattern_string = 'ATAG/GAGAAGATGATG/TATA' и query_string = 'ATAG/AGCAAGATGATG/TATA'. Это работает для следующего соответствия регулярному выражению:

r = regex.compile('(%s){e<=2}' % pattern_string)

r.match(query_string)

Здесь единственное изменение - между двумя / символами. Тем не менее, я хочу ограничить нечеткость совпадения разрешением только между этими символами, в то время как символы за пределами / остаются точными.

Например, pattern_string = 'ATGG/GAGAAGATGATG/TATA' и query_string = 'ATAG/AGCAAGATGATG/TATA' - это , а не совпадение, поскольку первая часть строки (ATGG против ATAG) не совпадает. Точно так же pattern_string = 'ATAG/GAGAAGATGATG/TATG' и query_string = 'ATAG/AGCAAGATGATG/TATA' также не совпадают, потому что последняя часть строки (TATG vs TATA) не совпадает.

Таким образом, часть строки в / (или любом символе-разделителе) должна иметь нечеткое совпадение в соответствии с тем, что указано в регулярном выражении ({e<=2} в этом случае), но строка вне быть точным совпадением.

Как этого достичь?

Я представляю себе функцию, подобную следующей

ideal_function(pattern_string, query_string)

Где

ideal_function(pattern_string = 'ATAG/GAGAAGATGATG/TATA', query_string = 'ATAG/AGCAAGATGATG/TATA') возвращает True ideal_function(pattern_string = 'ATGG/GAGAAGATGATG/TATA', query_string = 'ATAG/AGCAAGATGATG/TATA') возвращает False

Был бы признателен наиболее эффективный метод для этого, я должен сделать это для более чем 20 000 строк шаблонов с комбинацией из более чем 5 миллионов строк запросов, поэтому он должен быть максимально эффективным. Это не обязательно должно быть решением регулярных выражений, хотя оно должно поддерживать опцию разрешения нечеткого совпадения для заданного количества замен (как в {s<=2}) и количества ошибок (как в {e<=2}).

1 Ответ

1 голос
/ 16 марта 2019

Вы можете ограничить размытость раздела шаблона между слешами, используя следующую реализацию по вашему желанию ideal_function():

def ideal_function(pattern_string, query_string, fuzzy='e<=2'):
    prefix, body, suffix = pattern_string.split('/')
    r = regex.compile('%s/(%s){%s}/%s' % (prefix, body, fuzzy, suffix))
    return r.match(query_string) is not None

Вот оно в действии:

>>> ideal_function('ATAG/GAGAAGATGATG/TATA', 'ATAG/AGCAAGATGATG/TATA')
True

>>> ideal_function('ATGG/GAGAAGATGATG/TATA', 'ATAG/AGCAAGATGATG/TATA')
False

>>> ideal_function('ATAG/GAGAAGATGATG/TATA', 'ATAG/AGCAAGATGATG/TATA', 'e<=1')
False

>>> ideal_function('ATAG/GAGAAGATGATG/TATA', 'ATAG/AGCAAGATGATG/TATA', 'e<=2')
True

>>> ideal_function('ATAG/GAGAAGATGATG/TATA', 'ATAG/AGCAAGATGATG/TATA', 's<=2')
False

>>> ideal_function('ATAG/GAGAAGATGATG/TATA', 'ATAG/AGCAAGATGATG/TATA', 's<=3')
True

Это зависит от того, что вы всегда имеете в шаблоне ровно три разделенных косой чертой раздела, но поскольку для чего-то более обобщенного потребуется также указать, какие разделы нечеткие, а какие нет, я предполагаю, что этот простой подход подходит для вашего варианта использования.

Любая версия ideal_function(), которая должна создавать соответствующее регулярное выражение каждый раз, когда оно вызывается, вероятно, не будет самым эффективным подходом, кстати (хотя вам придется выполнить некоторое профилирование, чтобы определить, сколько разница, которая на самом деле имеет значение в вашем конкретном случае).

В зависимости от того, какой вывод вам нужен, что-то вроде этого может иметь больше смысла:

def ideal_generator(pattern_string, all_query_strings, fuzzy='e<=2'):
    prefix, body, suffix = pattern_string.split('/')
    r = regex.compile('%s/(%s){%s}/%s' % (prefix, body, fuzzy, suffix))
    for query_string in all_query_strings:
        if r.match(query_string) is not None:
            yield query_string

… что даст все строки запроса, соответствующие pattern_string.

...