fork(2) download
  1. import Data.Char
  2. import Data.List
  3.  
  4. digitRangeToRegex :: Integer -> Integer -> String
  5. digitRangeToRegex min max
  6. | min == max = digit min : ""
  7. -- uncomment if you want \d instead of [0-9]
  8. -- | min == 0 && max == 9 = "\\d"
  9. | min >= 10 || max <= 9 = "[" ++ rangeToStr (digit min) (digit max) ++ "]"
  10. | otherwise = "[" ++ rangeToStr (digit min) '9' ++ rangeToStr 'a' (digit max) ++ "]"
  11. where
  12. rangeToStr min max
  13. | min == max = min : ""
  14. | otherwise = min : '-' : max : ""
  15. digit d
  16. | d >= 0 && d <= 9 = chr (ord '0' + fromIntegral d)
  17. | d < 36 = chr (ord 'a' + fromIntegral d - 10)
  18.  
  19. numberRangeToRegex :: Integer -> Integer -> Integer -> String
  20. numberRangeToRegex base min max
  21. | min == 0 && max == 0 = "0"
  22. | cmin == cmax = intercalate "|" $ map formatRanges $ step dmin dmax
  23. | otherwise = intercalate "|" $
  24. (map formatRanges $ step dmin (replicate cmin (base-1))) ++
  25. (if cmin + 1 < cmax then [digitRangeToRegex 1 (base - 1) ++ digitRangeToRegex 0 (base-1) ++ formatCount cmin (cmax-2)] else []) ++
  26. (map formatRanges $ step (1 : replicate (cmax-1) 0) dmax)
  27. where
  28. digits 0 = [0]
  29. digits n = reverse $ map (`mod` base) $ takeWhile (>0) $ iterate (`div` base) n
  30. dmin = digits min
  31. dmax = digits max
  32. cmin = length dmin
  33. cmax = length dmax
  34. step [] [] = [[]]
  35. step (a:as) (b:bs) =
  36. if a == b then
  37. prepend a $ step as bs
  38. else
  39. (if zeroHead then [] else prepend a $ step as nines) ++
  40. (if na > nb then [] else [(na, nb) : replicate (length as) (0, base-1)]) ++
  41. (if nineTail then [] else prepend b $ step zeros bs)
  42. where
  43. suffixLen = length as
  44. zeroHead = all (== 0) as
  45. nineTail = all (== base-1) bs
  46. na = if zeroHead then a else a+1
  47. nb = if nineTail then b else b-1
  48. zeros = replicate suffixLen 0
  49. nines = replicate suffixLen (base-1)
  50. prepend x = map ((x, x):)
  51. formatRanges = concatMap formatGroup . group . dropWhile (== (0,0)) where
  52. formatGroup [(min, max)] = digitRangeToRegex min max
  53. formatGroup xs@((min, max) : _)
  54. | min == max = concat $ replicate (length xs) $ digitRangeToRegex min max
  55. | otherwise = digitRangeToRegex min max ++ "{" ++ show (length xs) ++ "}"
  56. formatCount min max
  57. | min == 1 && max == 1 = ""
  58. | min == max = "{" ++ show min ++ "}"
  59. | otherwise = "{" ++ show min ++ "," ++ show max ++ "}"
  60.  
  61. main = putStrLn $ numberRangeToRegex 10 42 100500
Success #stdin #stdout 0s 6240KB
stdin
Standard input is empty
stdout
4[2-9]|[5-9][0-9]|[1-9][0-9]{2,4}|100[0-4][0-9]{2}|100500