Haskell 2063+2*151=2365
It's guaranteed the generated regex has length O(log n log log n).
matchIntRange 12345 7654321
1(2(3(4(5[6-9]|[6-9]\d)|[5-9]\d\d)|[4-9]\d{3})|[3-9]\d{4})|[2-9]\d{5}|[1-6]\d{6}|7([0-5]\d{5}|6([0-4]\d{4}|5([0-3]\d{3}|4([012]\d\d|3([01]\d|2[01])))))
import Data.Digits
data RegEx = Range Int Int | MatchNone | All Int
| Or RegEx RegEx | Concat [RegEx]
alphabet = "\\d"
instance Show RegEx where
show (Range i j)
| i == j = show i
| i+1 == j = concat ["[",show i,show j,"]"]
| i+2 == j = concat ["[",show i,show (i+1), show (i+2),"]"]
| otherwise = concat ["[",show i,"-",show j,"]"]
show (Or a b) = show a ++ "|" ++ show b
show MatchNone = "^$"
show (All n)
| n < 3 = concat $ replicate n alphabet
| otherwise = concat [alphabet,"{",show n,"}"]
show e@(Concat xs)
| atomic e = concatMap show xs
| otherwise = concatMap show' xs
where show' (Or a b) = "("++show (Or a b)++")"
show' x = show x
atomic (Concat xs) = all atomic xs
atomic (Or _ _) = False
atomic _ = True
-- Match integers in a certain range
matchIntRange :: Int->Int->RegEx
matchIntRange a b
| 0 > min a b = error "Negative input"
| a > b = MatchNone
| otherwise = build (d a) (d b)
where build :: [Int]->[Int]->RegEx
build [] [] = Concat []
build (a@(x:xs)) (b@(y:ys))
| sl && x == y = Concat [Range x x, build xs ys]
| sl && all9 && all0 = Concat [Range x y, All n]
| sl && all0 = Or (Concat [Range x (y-1), All n]) upper
| sl && all9 = Or lower (Concat [Range (x+1) y, All n])
| sl && x+1 <= y-1 = Or (Or lower middle) upper
| sl = Or lower upper
| otherwise = Or (build a (nines la)) (build (1:zeros la) b)
where (la,lb) = (length a, length b)
sl = la == lb
n = length xs
upper = Concat [Range y y, build (zeros n) ys]
lower = Concat [Range x x, build xs (nines n)]
middle = Concat [Range (x+1) (y-1), All n]
all9 = all (==9) ys
all0 = all (==0) xs
zeros n = replicate n 0
nines n = replicate n 9
d 0 = [0]
d n = digits 10 n
The code below is a simple version that helps with understanding the algorithm, but it doesn't do any optimization to improve the regex size.
matchIntRange 123 4321
(((1((2((3|[4-8])|9)|[3-8]((0|[1-8])|9))|9((0|[1-8])|9))|[2-8]((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9)))|9((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9)))|((1((0((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9))|[1-8]((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9)))|9((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9)))|[2-3]((0((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9))|[1-8]((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9)))|9((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9))))|4((0((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9))|[1-2]((0((0|[1-8])|9)|[1-8]((0|[1-8])|9))|9((0|[1-8])|9)))|3((0((0|[1-8])|9)|1((0|[1-8])|9))|2(0|1)))))
The regular expression has 680 characters.
Here is the code
import Data.Digits
data RegEx = Range Int Int | MatchNone | Or RegEx RegEx | Concat [RegEx]
alphabet = "\\d"
instance Show RegEx where
show (Range i j)
| i == j = show i
| otherwise = concat ["[",show i,"-",show j,"]"]
show (Or a b) = concat ["(",show a,"|",show b,")"]
show MatchNone = "^$"
show (Concat xs) = concatMap show xs
matchIntRange :: Int->Int->RegEx
matchIntRange a b
| 0 > min a b = error "Negative input"
| a > b = MatchNone
| otherwise = build (d a) (d b)
where build :: [Int]->[Int]->RegEx
build [] [] = Concat []
build (a@(x:xs)) (b@(y:ys))
| sl && x == y = Concat [Range x x, build xs ys]
| sl && x+1 <= y-1 = Or (Or lower middle) upper
| sl = Or lower upper
| otherwise = Or (build a (nines la)) (build (1:zeros la) b)
where (la,lb) = (length a, length b)
sl = la == lb
n = length xs
upper = Concat [Range y y, build (zeros n) ys]
lower = Concat [Range x x, build xs (nines n)]
middle = Concat [Range (x+1) (y-1), build (zeros n) (nines n)]
zeros n = replicate n 0
nines n = replicate n 9
d 0 = [0]
d n = digits 10 n
re_size*5 + prog_size
(smaller = better), wherere_size
is the maximum form
andn
up to 5 digits. There are many other ways to do it - what matters is that we can grade the answers. \$\endgroup\$print .*
in some language. \$\endgroup\$if(min == 123456 && max == 7654321){print_hardcoded_regex}else{enumerate_range_and_join}
\$\endgroup\$