Реверсирование регулярного выражения в Python
Я хочу изменить регулярное выражение. То есть если вы используете регулярное выражение, я хочу создать любую строку, которая будет соответствовать этому регулярному выражению.
Я знаю, как это сделать с теоретической основы информатики, используя конечный автомат, но я просто хочу знать, кто-то уже написал библиотеку для этого.:)
Я использую Python, поэтому мне нужна библиотека Python.
Чтобы повторить, мне нужна только одна строка, которая будет соответствовать регулярному выражению. Вещи как "." или ". *" будет делать бесконечное количество строк, соответствующих регулярному выражению, но мне все равно, все варианты.
Я хочу, чтобы эта библиотека работала только с определенным подмножеством регулярного выражения.
Ответы
Ответ 1
У кого-то еще был подобный (дублированный?) вопрос здесь, и я хотел бы предложить небольшую вспомогательную библиотеку для генерирование случайных строк с Python, над которыми я работал.
Он включает в себя метод xeger()
, который позволяет вам создать строку из регулярного выражения:
>>> import rstr
>>> rstr.xeger(r'[A-Z]\d[A-Z] \d[A-Z]\d')
u'M5R 2W4'
Сейчас он работает с большинством основных регулярных выражений, но я уверен, что он может быть улучшен.
Ответ 2
Хотя я не вижу в этом особого смысла, здесь говорится:
import re
import string
def traverse(tree):
retval = ''
for node in tree:
if node[0] == 'any':
retval += 'x'
elif node[0] == 'at':
pass
elif node[0] in ['min_repeat', 'max_repeat']:
retval += traverse(node[1][2]) * node[1][0]
elif node[0] == 'in':
if node[1][0][0] == 'negate':
letters = list(string.ascii_letters)
for part in node[1][1:]:
if part[0] == 'literal':
letters.remove(chr(part[1]))
else:
for letter in range(part[1][0], part[1][1]+1):
letters.remove(chr(letter))
retval += letters[0]
else:
if node[1][0][0] == 'range':
retval += chr(node[1][0][1][0])
else:
retval += chr(node[1][0][1])
elif node[0] == 'not_literal':
if node[1] == 120:
retval += 'y'
else:
retval += 'x'
elif node[0] == 'branch':
retval += traverse(node[1][1][0])
elif node[0] == 'subpattern':
retval += traverse(node[1][1])
elif node[0] == 'literal':
retval += chr(node[1])
return retval
print traverse(re.sre_parse.parse(regex).data)
Я взял все из Regular Expression Syntax до групп - это похоже на разумное подмножество - и я проигнорировал некоторые детали, например конец строки. Обработка ошибок и т.д. Остается в качестве упражнения для читателя.
Из 12 специальных символов в регулярном выражении мы можем полностью игнорировать 6 (2 даже с атомом, к которому они применимы), 4.5 приводят к тривиальной замене и 1.5 заставляют нас думать.
То, что получается из этого, не слишком ужасно интересно, я думаю.
Ответ 3
Я не знаю ни одного модуля для этого. Если вы не найдете ничего подобного в Поваренной книге или PyPI, вы можете опробовать свою собственную, используя (недокументированный) модуль re.sre_parse. Это может помочь вам начать:
In [1]: import re
In [2]: a = re.sre_parse.parse("[abc]+[def]*\d?z")
In [3]: a
Out[3]: [('max_repeat', (1, 65535, [('in', [('literal', 97), ('literal', 98), ('literal', 99)])])), ('max_repeat', (0, 65535, [('in', [('literal', 100), ('literal', 101), ('literal', 102)])])), ('max_repeat', (0, 1, [('in', [('category', 'category_digit')])])), ('literal', 122)]
In [4]: eval(str(a))
Out[4]:
[('max_repeat',
(1, 65535, [('in', [('literal', 97), ('literal', 98), ('literal', 99)])])),
('max_repeat',
(0,
65535,
[('in', [('literal', 100), ('literal', 101), ('literal', 102)])])),
('max_repeat', (0, 1, [('in', [('category', 'category_digit')])])),
('literal', 122)]
In [5]: a.dump()
max_repeat 1 65535
in
literal 97
literal 98
literal 99
max_repeat 0 65535
in
literal 100
literal 101
literal 102
max_repeat 0 1
in
category category_digit
literal 122
Ответ 4
Если ваше регулярное выражение чрезвычайно просто (т.е. нет звезд или плюсов), будет бесконечно много строк, которые соответствуют ему. Если ваше регулярное выражение связано только с конкатенацией и чередованием, то вы можете развернуть каждое чередование во все свои возможности, например. (foo|bar)(baz|quux)
можно развернуть в список ['foobaz', 'fooquux', 'barbaz', 'barquux']
.
Ответ 5
В то время как другие ответы используют механизм re, чтобы проанализировать элементы, которые я взломал самостоятельно, который анализирует re и возвращает минимальный шаблон, который будет соответствовать. (Обратите внимание, что он не обрабатывает [^ ads], конструктивные конструкции группировки, специальные символы запуска/конца строки). Я могу предоставить модульные тесты, если вам действительно нравится:)
import re
class REParser(object):
"""Parses an RE an gives the least greedy value that would match it"""
def parse(self, parseInput):
re.compile(parseInput) #try to parse to see if it is a valid RE
retval = ""
stack = list(parseInput)
lastelement = ""
while stack:
element = stack.pop(0) #Read from front
if element == "\\":
element = stack.pop(0)
element = element.replace("d", "0").replace("D", "a").replace("w", "a").replace("W", " ")
elif element in ["?", "*"]:
lastelement = ""
element = ""
elif element == ".":
element = "a"
elif element == "+":
element = ""
elif element == "{":
arg = self._consumeTo(stack, "}")
arg = arg[:-1] #dump the }
arg = arg.split(",")[0] #dump the possible ,
lastelement = lastelement * int(arg)
element = ""
elif element == "[":
element = self._consumeTo(stack, "]")[0] # just use the first char in set
if element == "]": #this is the odd case of []<something>]
self._consumeTo(stack, "]") # throw rest away and use ] as first element
elif element == "|":
break # you get to an | an you have all you need to match
elif element == "(":
arg = self._consumeTo(stack, ")")
element = self.parse( arg[:-1] )
retval += lastelement
lastelement = element
retval += lastelement #Complete the string with the last char
return retval
def _consumeTo(self, stackToConsume, endElement ):
retval = ""
while not retval.endswith(endElement):
retval += stackToConsume.pop(0)
return retval
Ответ 6
Проверьте регулярное выражение в UtilityMill. (Исходный код доступен для просмотра на основе этого примера из вики файла pyparsing.)
Ответ 7
Я не видел модуль Python для этого, но я видел (частичную) реализацию в Perl: Regexp::Genex
, Из описания модуля это похоже на то, что реализация основывается на внутренних деталях движка регулярного выражения Perl, поэтому может быть не полезно даже с теоретической точки зрения (я не исследовал реализацию, просто переходя к комментариям в документации).
Я думаю, что делать то, что вы предлагаете в целом, является трудной проблемой и может потребовать использования методов недетерминированного программирования. Старт состоял бы в том, чтобы проанализировать регулярное выражение и построить дерево синтаксического анализа, затем пересечь дерево и построить образец образца, когда вы идете. Сложные биты, вероятно, будут такими, как обратные ссылки и избегающие бесконечных циклов в вашей реализации.
Ответ 8
Exrex может создавать строки из регулярных выражений.
Exrex - это инструмент командной строки и модуль python, который генерирует все или произвольные строки соответствия для данного регулярного выражения и т.д.
Пример:
>>> exrex.getone('\d{4}-\d{4}-\d{4}-[0-9]{4}')
'3096-7886-2834-5671'