fork download
  1. {-# LANGUAGE LambdaCase #-}
  2.  
  3. import Prelude hiding (any)
  4. import System.Random
  5. import Text.ParserCombinators.ReadP hiding (option)
  6.  
  7. data Entity
  8. = Single Char
  9. | Any
  10. | Range Char Char
  11. | Option [CountedEntity]
  12. deriving Show
  13.  
  14. data CountedEntity
  15. = One Entity
  16. | OneOrMore Entity
  17. | Many Entity
  18. deriving Show
  19.  
  20. type Regex = [CountedEntity]
  21.  
  22. main :: IO ()
  23. main = do
  24. g <- getStdGen
  25. . zipWith genRegex (gens g)
  26. . map parseRegex
  27.  
  28. gens :: RandomGen g => g -> [g]
  29. gens g = let ~(g0, g1) = split g in g0 : gens g1
  30.  
  31. parseRegex :: String -> Regex
  32. parseRegex = fst . head . readP_to_S regex
  33.  
  34. regex :: ReadP Regex
  35. regex = manyTill countedEntity eof
  36.  
  37. countedEntity :: ReadP CountedEntity
  38. countedEntity = do
  39. e <- entity
  40. choice
  41. [ OneOrMore e <$ char '+'
  42. , Many e <$ char '*'
  43. , return $ One e
  44. ]
  45.  
  46. entity :: ReadP Entity
  47. entity = choice [option, range, any, single]
  48.  
  49. option :: ReadP Entity
  50. option = Option <$> between (char '[') (char ']') (many countedEntity)
  51.  
  52. range :: ReadP Entity
  53. range = do
  54. a <- simpleChar
  55. char '-'
  56. b <- simpleChar
  57. return $ Range a b
  58.  
  59. any :: ReadP Entity
  60. any = Any <$ char '.'
  61.  
  62. single :: ReadP Entity
  63. single = Single <$> simpleChar
  64.  
  65. simpleChar :: ReadP Char
  66. simpleChar = choice
  67. [ char '\\' *> get
  68. , satisfy (`notElem` ".+*[]-")
  69. ]
  70.  
  71. genRegex :: RandomGen g => g -> Regex -> String
  72. genRegex g = concat . zipWith genCountedEntity (gens g)
  73.  
  74. genCountedEntity :: RandomGen g => g -> CountedEntity -> String
  75. genCountedEntity g = \case
  76. One e -> genEntity g e
  77. OneOrMore e -> more (n + 1) e
  78. Many e -> more n e
  79. where
  80. (n, g') = randomR (0, 10) g -- arbitrary limit of 10
  81. more x = concat
  82. . zipWith genEntity (gens g')
  83. . replicate x
  84.  
  85. genEntity :: RandomGen g => g -> Entity -> String
  86. genEntity g = \case
  87. Single c -> [c]
  88. Any -> [fst $ random g]
  89. Range a b -> [fst $ randomR (a, b) g]
  90. Option es ->
  91. let (n, g') = randomR (0, length es - 1) g
  92. in genCountedEntity g' (es !! n)
Success #stdin #stdout 0s 8388607KB
stdin
a+b
abc*d
[A-Za-z0-9$.+!*'(){},~:;=@#%_\-]*
ab[c-l]+jkm9*10+
iqb[beoqob-q]872+0qbq*
stdout
aab
abccccd
:,~#
abcgjfjcgfgdjkm9999910000000000
iqbe87220qbqqq