这是我的63行F(包括一个测试用例);它第一次工作,我觉得它很可读。它是典型的解析器,后面是漂亮的打印机。我们怎么想?
type IPs = IP[]
and IP = IP of OrParts * OrParts * OrParts * OrParts
and OrParts = Or of Part[]
and Part = Num of int | Range of int * int
let Valid(x) = if x < 0 || x > 255 then failwithf "Invalid number %d" x
let rec parseIPs (s:string) =
s.Split [|';'|] |> Array.map parseIP
and parseIP s =
let [|a;b;c;d|] = s.Split [|'.'|]
IP(parseOrParts a, parseOrParts b, parseOrParts c, parseOrParts d)
and parseOrParts s =
Or(s.Split [|','|] |> Array.map parsePart)
and parsePart s =
if s.Contains("-") then
let [|a;b|] = s.Split [|'-'|]
let x,y = int a, int b
Valid(x)
Valid(y)
if x > y then failwithf "Invalid range %d-%d" x y
Range(x, y)
else
let x = int s
Valid(x)
Num(x)
let rec printIPsAsRegex ips =
let sb = new System.Text.StringBuilder()
let add s = sb.Append(s:string) |> ignore
add "("
add(System.String.Join("|", ips |> Array.map printIPAsRegex))
add ")"
sb.ToString()
and printIPAsRegex (IP(a, b, c, d)) : string =
let sb = new System.Text.StringBuilder()
let add s = sb.Append(s:string) |> ignore
add "("
printPartsAsRegex add a
add "."
printPartsAsRegex add b
add "."
printPartsAsRegex add c
add "."
printPartsAsRegex add d
add ")"
sb.ToString()
and printPartsAsRegex add (Or(parts)) =
match parts with
| [| Num x |] -> // exactly one Num
add(string x)
| _ ->
add "("
add(System.String.Join("|", parts |> Array.collect (function
| Num x -> [| x |]
| Range(x,y) -> [| x..y |])
|> Array.map (fun x -> x.ToString())))
add ")"
let Main() =
let ips = parseIPs "192.168.0.250,244-248,108,51,7;127.0.0.1"
printfn "%s" (printIPsAsRegex ips)
Main()