Как это можно сделать в регулярном выражении?
Вы можете использовать модуль регулярных выражений PyPi, который имеет встроенную технику нечеткого сопоставления. Этот метод нечеткости позволяет вам указать, что может происходить с строкой, а что нет, с точки зрения ошибок регулярных выражений, сколько допустимо, а также оценка для каждого типа ошибки нечеткого сопоставления. Эту информацию можно найти здесь .
В терминах регулярного выражения вы должны использовать следующее (очевидно, если указанное вами в вашем вопросе регулярное выражение задано заранее, вы можете объединить его;prepend (?:
и append ){e}
):
(?:abc.*Pickles.*efg){e}
В приведенном выше регулярном выражении {e}
допускает любой тип ошибки (удаление, вставка, замена) при сопоставлении строки. Вы можете изменить это по своему вкусу, некоторые примеры перечислены ниже (многие скопированы по ссылке, указанной в первом абзаце):
{d}
только удаление {d,i}
удалениеи только вставка {d,s,i}
удаление, замена или вставка (аналогично {e}
) - порядок не имеет значения {e<=3}
допускает не более 3 ошибок {i<3}
разрешить менее 3 вставок {1<=e<3}
разрешить не менее 1 ошибки, но менее 3 ошибок {1<=2,d>2}
разрешить не более 2 вставок, разрешить не менее 2 удалений {2i+d2+1s<=4}
каждая вставка стоит 2, каждое удаление стоит 2, каждая замена стоит 1, общая стоимость не должна превышать 4 {i<=1,d<=1,s<=1,2i+2d+1s<=4}
не более 1 вставки, не более 1 удаления, не более 1замещение;каждая вставка стоит 2, каждое удаление стоит 2, каждая замена стоит 1, общая стоимость не должна превышать 4
Как выглядит ее реализация?
Теперь, когда выиметь представление о том, что это такое и как это работает, мы можем перейти к фактической реализации. Приведенный ниже код использует в вычислениях модуль регулярных выражений fuzzy_counts
, чтобы определить лучшую строку на основе ее оценки. Мой расчет преобразуется в процент и работает следующим образом (вы можете изменить его по своему вкусу и, в сочетании с информацией выше, изменить оценки для каждого типа ошибок, с которыми сталкивается регулярное выражение):
# 100 * (1 - (fuzziness/length of original string))
100*(1 - (n/len(s)))
Смотрите этот код, работающий здесь
Примечание: я использовал pprint
, чтобы красиво отобразить вывод;нет необходимости использовать его, просто облегчает чтение результатов.
import regex, pprint
strings = [
"abc_Pickled_efg",
"abc_Pickller_efg",
"abcd_something_Picklesefgh",
"efg_Pickles_abc"
]
r = r'(?:abc.*Pickles.*efg){e}'
matches = []
for i,s in enumerate(strings):
x = regex.fullmatch(r,s, regex.BESTMATCH) # match result
n = sum(x.fuzzy_counts) # fuzziness
c = 100*(1 - (n/len(s))) # closeness
matches.append(c)
result = sorted(zip(strings, matches),key=lambda x: x[1],reverse=True)
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(result)
И результат:
[ ('abcd_something_Picklesefgh', 96.15384615384616),
('abc_Pickled_efg', 93.33333333333333),
('abc_Pickller_efg', 87.5),
('efg_Pickles_abc', 60.0)]