fork(3) download
  1.  
  2. import sre_parse
  3. import pprint
  4. import random
  5.  
  6.  
  7. class RandomRegexStringGenerator:
  8. def __init__(self):
  9. self._words = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
  10. self._digits = '0123456789'
  11. self._puncts = '!"#$%&()*+,-./:;<=>?@[\]^_`{|}~'
  12. self._whitespaces = ' \t' # ' \t\n\r\v\f' 에서 조정
  13. self._max_repeat = 5 # 무한 수량자가 나왔을때 최대 반복 리밋
  14. self._result = ''
  15.  
  16. def _gen_char(self, value):
  17. return chr(value)
  18.  
  19. def _gen_range(self, min_value, max_value):
  20. # random 선택
  21. idx = random.randint(min_value, max_value)
  22. return chr(idx)
  23.  
  24. def _gen_in_word(self):
  25. return self._words[random.randint(0, len(self._words)-1)]
  26.  
  27. def _gen_in_digit(self):
  28. return self._digits[random.randint(0, len(self._digits)-1)]
  29.  
  30. def _gen_in_whitespace(self):
  31. return self._whitespaces[random.randint(0, len(self._whitespaces)-1)]
  32.  
  33. def _gen_in_punct(self):
  34. return self._puncts[random.randint(0, len(self._puncts)-1)]
  35.  
  36. def _gen_class(self, cls_itm):
  37. if cls_itm[0] == sre_parse.LITERAL:
  38. self._result += self._gen_char(cls_itm[1])
  39.  
  40. elif cls_itm[0] == sre_parse.RANGE:
  41. self._result += self._gen_range(cls_itm[1][0], cls_itm[1][1])
  42.  
  43. elif cls_itm[0] == sre_parse.CATEGORY:
  44. if cls_itm[1] == sre_parse.CATEGORY_DIGIT:
  45. self._result += self._gen_in_digit()
  46.  
  47. elif cls_itm[1] == sre_parse.CATEGORY_WORD:
  48. self._result += self._gen_in_word()
  49.  
  50. elif cls_itm[1] == sre_parse.CATEGORY_SPACE:
  51. self._result += self._gen_in_whitespace()
  52.  
  53. elif cls_itm[1] == sre_parse.CATEGORY_NOT_DIGIT:
  54. self._result += self._gen_in_punct() # NOT-DIGIT => PUNCT
  55.  
  56. elif cls_itm[1] == sre_parse.CATEGORY_NOT_WORD:
  57. self._result += self._gen_in_punct() # NOT-WORD => PUNCT
  58.  
  59. elif cls_itm[1] == sre_parse.CATEGORY_NOT_SPACE:
  60. self._result += self._gen_in_word() # NOT-SPACE => WORD
  61.  
  62. def _gen_negate_class(self, body):
  63. # 문자클래스에 속하지 않는 문자 랜덤 지정
  64. # 완전 랜덤은 아니며 min, max 근방의 값으로 함
  65. min_value = 9999999
  66. max_value = 32
  67. for cls_itm in body:
  68. if cls_itm[0] == sre_parse.LITERAL:
  69. min_value = min(cls_itm[1], min_value)
  70. max_value = max(cls_itm[1], max_value)
  71. elif cls_itm[0] == sre_parse.RANGE:
  72. min_value = min(cls_itm[1][0], min_value)
  73. max_value = max(cls_itm[1][1], max_value)
  74.  
  75. if min_value-1 >= 32:
  76. # random 선택
  77. self._result += chr( random.randint(32, min_value-1) )
  78. else:
  79. if max_value + 1 <= 126:
  80. self._result += chr( random.randint(max_value + 1, 126) )
  81. else:
  82. # ascii 범위 벗어남, 그냥 표정
  83. self._result += chr( random.randint(0x1F600, 0x1F609) )
  84.  
  85.  
  86.  
  87.  
  88. def _proc_cmd(self, itm):
  89. # 단문자
  90. if itm[0] == sre_parse.LITERAL:
  91. self._result += self._gen_char(itm[1])
  92.  
  93. # 문자클래스
  94. elif itm[0] == sre_parse.IN:
  95. start_num = 0
  96. body = itm[1]
  97. if body[0][0] == sre_parse.NEGATE: # 제외조건 TODO:
  98. start_num = 1
  99. self._gen_negate_class(body[1:])
  100. else:
  101. # random 선택
  102. idx = random.randint(start_num, len(body)-1)
  103. cls_itm = body[idx]
  104. self._gen_class(cls_itm)
  105.  
  106. # 수량자
  107. elif itm[0] in (sre_parse.MAX_REPEAT, sre_parse.MIN_REPEAT):
  108. # 패턴 => XXX_REPEAT, (min, max, p)
  109. min_repeat = itm[1][0]
  110. max_repeat = itm[1][1]
  111. # set limit
  112. if itm[1][1] == sre_parse.MAXREPEAT:
  113. max_repeat = self._max_repeat # 지정한 max값으로 한정
  114.  
  115. # random 선택
  116. rand_repeat = random.randint(min_repeat, max_repeat)
  117.  
  118. # random 만큼 반복
  119. for i in range(rand_repeat):
  120. self._read_body(itm[1][2])
  121.  
  122. # Union
  123. elif itm[0] == sre_parse.BRANCH:
  124. body = itm[1][1]
  125. # random 선택
  126. idx = random.randint(0, len(body)-1)
  127. self._read_body(body[idx])
  128.  
  129. else:
  130. if isinstance(itm[1], tuple):
  131. for titm in itm[1]:
  132. if isinstance(titm, sre_parse.SubPattern):
  133. #print('CMD: %s in body '%(itm[0]))
  134. self._read_body(titm)
  135.  
  136. # [ (cmd), (cmd), ...] 이런 형태에 대해 cmd 마다 처리
  137. def _read_body(self, body):
  138. for itm in body:
  139. self._proc_cmd(itm)
  140.  
  141.  
  142. def generate(self, regex_pattern):
  143.  
  144. p = sre_parse.parse( regex_pattern )
  145. #pprint.pprint(p)
  146.  
  147. self._result = ''
  148. self._read_body( p )
  149.  
  150. return self._result
  151.  
  152.  
  153. pats = [
  154. r'01[069]-\d{3}\d?-\d{4}', # 전화번호
  155. r'안녕하세요 제 이름은 [김이박최황안][가-힣][가-힣] (입니다|일까요\?)', # 유니코드
  156. r'aa(bcd|\w{7}\d{3}|[a-z0-9]+)cc\W{2}\S{2}\D{2}', # union 수량자
  157. 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
  158. r'[^ -~a-z]+', # ascii printable 범위 제외 문자클래스 => 그냥 유니코드 표정
  159. ]
  160.  
  161.  
  162.  
  163. g = RandomRegexStringGenerator()
  164.  
  165. for pat in pats:
  166. print('pattern=>', pat)
  167. for i in range(3):
  168. print( g.generate( pat ) )
  169. print('--------')
  170.  
  171.  
Success #stdin #stdout 0.04s 12200KB
stdin
Standard input is empty
stdout
pattern=> 01[069]-\d{3}\d?-\d{4}
016-8808-1054
010-6852-5285
019-7930-0908
--------
pattern=> 안녕하세요 제 이름은 [김이박최황안][가-힣][가-힣] (입니다|일까요\?)
안녕하세요 제 이름은 박픲냠 일까요?
안녕하세요 제 이름은 안놺샯 입니다
안녕하세요 제 이름은 박꼶뿽 입니다
--------
pattern=> aa(bcd|\w{7}\d{3}|[a-z0-9]+)cc\W{2}\S{2}\D{2}
aak56cc|>_4%{
aabcdcc)}Zp+>
aabcdcc-`Ak")
--------
pattern=> (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}\);
void qF_b45c0n (char WuLy, int TQsu);
double tHFl3jNvK (int _84Q, int _Maz, int rniw);
double iDiqhZ7rQ (char wtRo, int x13y);
--------
pattern=> [^ -~a-z]+
😅😉
😈
😂
--------