Подтвердить что ты не робот

Реверсирование регулярного выражения в Python

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

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

Я использую Python, поэтому мне нужна библиотека Python.

Чтобы повторить, мне нужна только одна строка, которая будет соответствовать регулярному выражению. Вещи как "." или ". *" будет делать бесконечное количество строк, соответствующих регулярному выражению, но мне все равно, все варианты.

Я хочу, чтобы эта библиотека работала только с определенным подмножеством регулярного выражения.

4b9b3361

Ответ 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

Ответ 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'