import sre_parse
import pprint
import random
class RandomRegexStringGenerator:
def __init__(self):
self._words = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
self._digits = '0123456789'
self._puncts = '!"#$%&()*+,-./:;<=>?@[\]^_`{|}~'
self._whitespaces = ' \t' # ' \t\n\r\v\f' 에서 조정
self._max_repeat = 5 # 무한 수량자가 나왔을때 최대 반복 리밋
self._result = ''
def _gen_char(self, value):
return chr(value)
def _gen_range(self, min_value, max_value):
# random 선택
idx = random.randint(min_value, max_value)
return chr(idx)
def _gen_in_word(self):
return self._words[random.randint(0, len(self._words)-1)]
def _gen_in_digit(self):
return self._digits[random.randint(0, len(self._digits)-1)]
def _gen_in_whitespace(self):
return self._whitespaces[random.randint(0, len(self._whitespaces)-1)]
def _gen_in_punct(self):
return self._puncts[random.randint(0, len(self._puncts)-1)]
def _gen_class(self, cls_itm):
if cls_itm[0] == sre_parse.LITERAL:
self._result += self._gen_char(cls_itm[1])
elif cls_itm[0] == sre_parse.RANGE:
self._result += self._gen_range(cls_itm[1][0], cls_itm[1][1])
elif cls_itm[0] == sre_parse.CATEGORY:
if cls_itm[1] == sre_parse.CATEGORY_DIGIT:
self._result += self._gen_in_digit()
elif cls_itm[1] == sre_parse.CATEGORY_WORD:
self._result += self._gen_in_word()
elif cls_itm[1] == sre_parse.CATEGORY_SPACE:
self._result += self._gen_in_whitespace()
elif cls_itm[1] == sre_parse.CATEGORY_NOT_DIGIT:
self._result += self._gen_in_punct() # NOT-DIGIT => PUNCT
elif cls_itm[1] == sre_parse.CATEGORY_NOT_WORD:
self._result += self._gen_in_punct() # NOT-WORD => PUNCT
elif cls_itm[1] == sre_parse.CATEGORY_NOT_SPACE:
self._result += self._gen_in_word() # NOT-SPACE => WORD
def _gen_negate_class(self, body):
# 문자클래스에 속하지 않는 문자 랜덤 지정
# 완전 랜덤은 아니며 min, max 근방의 값으로 함
min_value = 9999999
max_value = 32
for cls_itm in body:
if cls_itm[0] == sre_parse.LITERAL:
min_value = min(cls_itm[1], min_value)
max_value = max(cls_itm[1], max_value)
elif cls_itm[0] == sre_parse.RANGE:
min_value = min(cls_itm[1][0], min_value)
max_value = max(cls_itm[1][1], max_value)
if min_value-1 >= 32:
# random 선택
self._result += chr( random.randint(32, min_value-1) )
else:
if max_value + 1 <= 126:
self._result += chr( random.randint(max_value + 1, 126) )
else:
# ascii 범위 벗어남, 그냥 표정
self._result += chr( random.randint(0x1F600, 0x1F609) )
def _proc_cmd(self, itm):
# 단문자
if itm[0] == sre_parse.LITERAL:
self._result += self._gen_char(itm[1])
# 문자클래스
elif itm[0] == sre_parse.IN:
start_num = 0
body = itm[1]
if body[0][0] == sre_parse.NEGATE: # 제외조건 TODO:
start_num = 1
self._gen_negate_class(body[1:])
else:
# random 선택
idx = random.randint(start_num, len(body)-1)
cls_itm = body[idx]
self._gen_class(cls_itm)
# 수량자
elif itm[0] in (sre_parse.MAX_REPEAT, sre_parse.MIN_REPEAT):
# 패턴 => XXX_REPEAT, (min, max, p)
min_repeat = itm[1][0]
max_repeat = itm[1][1]
# set limit
if itm[1][1] == sre_parse.MAXREPEAT:
max_repeat = self._max_repeat # 지정한 max값으로 한정
# random 선택
rand_repeat = random.randint(min_repeat, max_repeat)
# random 만큼 반복
for i in range(rand_repeat):
self._read_body(itm[1][2])
# Union
elif itm[0] == sre_parse.BRANCH:
body = itm[1][1]
# random 선택
idx = random.randint(0, len(body)-1)
self._read_body(body[idx])
else:
if isinstance(itm[1], tuple):
for titm in itm[1]:
if isinstance(titm, sre_parse.SubPattern):
#print('CMD: %s in body '%(itm[0]))
self._read_body(titm)
# [ (cmd), (cmd), ...] 이런 형태에 대해 cmd 마다 처리
def _read_body(self, body):
for itm in body:
self._proc_cmd(itm)
def generate(self, regex_pattern):
p = sre_parse.parse( regex_pattern )
#pprint.pprint(p)
self._result = ''
self._read_body( p )
return self._result
pats = [
r'01[069]-\d{3}\d?-\d{4}', # 전화번호
r'안녕하세요 제 이름은 [김이박최황안][가-힣][가-힣] (입니다|일까요\?)', # 유니코드
r'aa(bcd|\w{7}\d{3}|[a-z0-9]+)cc\W{2}\S{2}\D{2}', # union 수량자
r'(void|char|int|double) [A-Za-z_]\w{8} \((int|char) [A-Za-z_]\w{3}(, (int|char) [A-Za-z_]\w{3}){1,2}\);', # function style
r'[^ -~a-z]+', # ascii printable 범위 제외 문자클래스 => 그냥 유니코드 표정
]
g = RandomRegexStringGenerator()
for pat in pats:
print('pattern=>', pat)
for i in range(3):
print( g.generate( pat ) )
print('--------')