我想反转正则表达式。 IE。给定一个正则表达式,我想生成与该正则表达式匹配的any字符串。
我知道如何从理论计算机科学背景使用有限状态机来做到这一点,但我只想知道是否有人已经编写了一个库来做到这一点。 :)
我正在使用 Python,所以我想要一个 Python 库。
重申一下,我只想要 one 与正则表达式匹配的字符串。像“.”之类的东西或“.*”将使无限数量的字符串与正则表达式匹配,但我不关心所有选项。
我愿意这个库只适用于正则表达式的某个子集。
其他人也有类似的(重复?)问题here,我想提供一个小帮助库,用于我一直在研究的使用Python生成随机字符串。
它包含一个方法,xeger()
,允许您从正则表达式创建字符串:
>>> import rstr
>>> rstr.xeger(r'[A-Z]\d[A-Z] \d[A-Z]\d')
u'M5R 2W4'
目前,它适用于最基本的正则表达式,但我确信它可以改进。
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)
我采用了从
正则表达式语法到组的所有内容——这似乎是一个合理的子集——并且我忽略了一些细节,例如行结尾。错误处理等留给读者作为练习。
在正则表达式中的 12 个特殊字符中,我们可以完全忽略 6 个(其中 2 个甚至可以忽略它们所适用的原子),4.5 个导致简单的替换,1.5 个让我们真正思考。我认为,由此产生的结果并不是太有趣。
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
Exrex 可以从正则表达式创建字符串。
Exrex 是一个命令行工具和 python 模块,可生成与给定正则表达式等的所有或随机匹配的字符串。示例:
>>> exrex.getone('\d{4}-\d{4}-\d{4}-[0-9]{4}')
'3096-7886-2834-5671'
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
(foo|bar)(baz|quux)
可以扩展到列表
['foobaz', 'fooquux', 'barbaz', 'barquux']
。
hypothesis
包有一个策略
from_regex
,它正是这样做的:
>>> from hypothesis import strategies as st
>>> regex_strategy = st.from_regex(r'[0-9]{4}-[0-9]{8}-[0-9]{16}', fullmatch=True)
>>> regex_strategy.example()
'5000-00000000-0000000000000000'
>>> regex_strategy.example()
'8934-72779254-0542308893797380'
>>> regex_strategy.example()
'0000-00000000-0000000000000000'
>>> regex_strategy.example()
'9000-00000000-0000000000000000'
>>> regex_strategy.example()
'2791-03881838-5840296980736661'
请注意,hypothesis
是一个用于模糊测试的库,而不仅仅是一个简单的数据生成器。因此建议谨慎:如果您将上面示例中的模式修改为
\d{4}-\d{8}-\d{16}
,生成的示例可能类似于
'۵෫൮۹-๕꯱౦໓᠘௮᭒৮-꯳೩꘥៦६༣𑶣߃੮8༡႑۹᪒٩꧶'
,这可能看起来出乎意料,但与模式匹配。
regex-enumerator 的 Python 库,它可以枚举与有限正则表达式匹配的所有字符串。如果您愿意使用 Python 来完成您的任务,这个库可能会有用。它在 PyPI 上可用,因此您可以使用以下命令轻松安装它:
pip install regex-enumerator
以下是如何使用它的示例:
from regex_enumerator import RegexEnumerator
# Initialize the RegexEnumerator with your regex pattern
re = RegexEnumerator(r'a[0-9]b')
# Generate strings that match the pattern, one at a time
print(re.next()) # a0b
print(re.next()) # a1b
print(re.next()) # a2b
该库专为您需要系统地枚举正则表达式的所有可能匹配的情况而设计,使其适合诸如详尽测试或生成数据集之类的任务。虽然最初的问题专门要求 Java 解决方案,但如果您愿意利用 Python,则该库可以作为替代方法。