代码之家  ›  专栏  ›  技术社区  ›  Phobis

在这个特定的例子(IP地址表达式)中,有人能帮我比较使用F_over C_吗?

f# c#
  •  0
  • Phobis  · 技术社区  · 14 年前

    所以,我正在编写代码来解析和IP地址表达式,并将其转换为一个正则表达式,可以对和IP地址字符串运行,并返回一个布尔响应。我用C(OO)编写了代码,共有110行代码。我试图比较代码的数量和C到F的表达能力(我是C程序员,F的noob)。我不想把C和F都贴出来,只是因为我不想把文章弄乱。如果需要,我会这样做。

    无论如何,我会举个例子。下面是一个表达式:

    192.168.0.250244-248108,51,7;127.0.0.1

    我想把它转换成这个正则表达式:

    ((192 \.168 \.0 \.(250 244 245 246 247 248 108 51 7))(127 \.0 \.0 \.1))

    以下是我要遵循的一些步骤:

    操作:

    破折号“;192.168.0.250244-248108、51、7 127.0.0.1

    按“.”192 168 0 250244-248108、51、7中断

    断开“,”250 244-248 108 51 7 以“-”分隔244 248

    我想出了产生输出的f。我正试图通过上面列出的操作转发管道,因为我认为这更具表现力。有人能把这个代码做得更好吗?教我点东西:)

    open System
    
    let createItemArray (group:bool) (y:char) (items:string[]) = 
      [|
        let indexes = items.Length - 1
        let group = indexes > 0 && group
        if group then
          yield "("
        for i in 0 .. indexes do
          yield items.[i].ToString()
          if i < indexes then
            yield y.ToString()
        if group then
          yield ")"
      |] 
    
    let breakBy (group:bool) (x:string) (y:char): string[] = 
      x.Split(y)
        |> createItemArray group y 
    
    let breakItem  (x:string) (y:char): string[] = breakBy false x y
    let breakGroup  (x:string) (y:char): string[] = breakBy true x y
    
    let AddressExpression address:string = 
        let builder = new System.Text.StringBuilder "("
        breakGroup address ';'
        |> Array.collect (fun octet -> breakItem octet '.')
        |> Array.collect (fun options -> breakGroup options ',')
        |> Array.collect (fun (ranges : string) -> 
                                match (breakGroup ranges '-') with
                                | x when x.Length > 3
                                  -> match (Int32.TryParse(x.[1]), Int32.TryParse(x.[3]))    with
                                      | ((true, a) ,(true, b))
                                          -> [|a .. b|]
                                              |> Array.map (int >> string)
                                              |> createItemArray false '-'
                                      | _ -> [|ranges|]
                                | _ -> [|ranges|]
                        )
        |> Array.iter (fun item ->
                        match item with
                        | ";" -> builder.Append ")|("
                        | "." -> builder.Append "\."
                        | "," | "-" -> builder.Append "|"
                        | _ -> builder.Append item
                        |> ignore
                      )
        builder.Append(")").ToString()
    
    let address = "192.168.0.250,244-248,108,51,7;127.0.0.1"
    AddressExpression address
    
    1 回复  |  直到 14 年前
        1
  •  3
  •   Brian    14 年前

    这是我的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()