{-# LANGUAGE LambdaCase #-} import Prelude hiding (any) import System.Random import Text.ParserCombinators.ReadP hiding (option) data Entity = Single Char | Any | Range Char Char | Option [CountedEntity] deriving Show data CountedEntity = One Entity | OneOrMore Entity | Many Entity deriving Show type Regex = [CountedEntity] main :: IO () main = do g <- getStdGen interact $ unlines . zipWith genRegex (gens g) . map parseRegex . lines gens :: RandomGen g => g -> [g] gens g = let ~(g0, g1) = split g in g0 : gens g1 parseRegex :: String -> Regex parseRegex = fst . head . readP_to_S regex regex :: ReadP Regex regex = manyTill countedEntity eof countedEntity :: ReadP CountedEntity countedEntity = do e <- entity choice [ OneOrMore e <$ char '+' , Many e <$ char '*' , return $ One e ] entity :: ReadP Entity entity = choice [option, range, any, single] option :: ReadP Entity option = Option <$> between (char '[') (char ']') (many countedEntity) range :: ReadP Entity range = do a <- simpleChar char '-' b <- simpleChar return $ Range a b any :: ReadP Entity any = Any <$ char '.' single :: ReadP Entity single = Single <$> simpleChar simpleChar :: ReadP Char simpleChar = choice [ char '\\' *> get , satisfy (`notElem` ".+*[]-") ] genRegex :: RandomGen g => g -> Regex -> String genRegex g = concat . zipWith genCountedEntity (gens g) genCountedEntity :: RandomGen g => g -> CountedEntity -> String genCountedEntity g = \case One e -> genEntity g e OneOrMore e -> more (n + 1) e Many e -> more n e where (n, g') = randomR (0, 10) g -- arbitrary limit of 10 more x = concat . zipWith genEntity (gens g') . replicate x genEntity :: RandomGen g => g -> Entity -> String genEntity g = \case Single c -> [c] Any -> [fst $ random g] Range a b -> [fst $ randomR (a, b) g] Option es -> let (n, g') = randomR (0, length es - 1) g in genCountedEntity g' (es !! n)