hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

question to file parsing

Last post 06-03-2008, 7:16 by gneverov. 3 replies.
Sort Posts: Previous Next
  •  05-29-2008, 12:26 6031

    question to file parsing

    Hi all,

    i am just learning F# (coming from a C/C++/C# world) and have a hard time to understand this starnge new & fascinating world.

    For that purpose i try to write some kind of logfile-parser (IIS-Logs, actually) & now i hit the following wall:

    i read in the IIS logfile and mapped it to a string-array. (Thanks to Don Syme's Expert F# book...)

    Now I want to parse that array for occurences of a certain string pattern and write out the the index of the array-elements into a list.

    Then i want to split that array at these elements into new arrays, so that i have several arrays with the first element always the one with the string-pattern.

    I would like to do this in a _as_least_imperative_as_possible_ & _as_pure_as_possible_

    Is it possible to help me with a code snippet for that purpose? Would be really great!    

    Thank you in advance for your *very* appreciated help,

    - Karl

  •  05-31-2008, 12:00 6045 in reply to 6031

    Re: question to file parsing

    OK, I tried several things & what i can come up with is the code sequence below.
    I use a ref that i thread through  Seq.choose. Looks not too elegant, but nevertheless...

    
    

    #light open System open System.IO open System.Text let logfile =    seq { use reader = new StreamReader(File.OpenRead(@"C:\Karl\YALP\ex080508.log"))           while not reader.EndOfStream do

               yield reader.ReadLine() } let i = ref 0 let r = logfile |>
        Seq.choose
    (
    fun x ->
    incr i
                let y = String.split [' '] x
                 let z = List.hd y
                 
    if z = "#Date:" then
    Some ((sprintf "%d" !i)::y) else None)

    Looks not quite right for me...
    Especially the sprintf & the incr.

    Maybe someone can point me to the right direction....

    Thank you & enjoy your weekend!

    - Karl

     

     
  •  05-31-2008, 17:02 6047 in reply to 6045

    Re: question to file parsing

    I haven't looked at your problem very closely, but i would probably annotate each line in the sequence with the index of the line:

    let logfile' = Seq.mapi (fun idx line -> (idx, line)) logfile

    and then filter the tuple sequence based on the contents of the lines.
  •  06-03-2008, 7:16 6061 in reply to 6031

    Re: question to file parsing

    Hi KarlTi,

    Here is a purely functional piece of code to do what I think you are looking for. I think your second post wasn't doing the "Then i want to split that array..." part. The code below does just that, in fact it skips the intermediate step of getting the list of indexes altogether. Sometimes thinking what you would do imperatively is counter-productive when programming functionally. In this case trying to create an intermediate list of indexes makes the functional solution harder and less efficient.

    let f p xs =
      let f xs =
        match xs with
        | [] -> None
        | x::xs' -> let ys, zs = break p xs'
                    Some (x::ys, zs)
      unfold f xs

    let result = f (fun (x : string) -> x.StartsWith("#Date:")) logfile

    This code uses lists and the following general-purpose helper functions. You could do the same thing with sequences, but it is harder and less educational about (pure) functional programming.

    let unfold f x =
      let rec unfold' x acc =
        match f x with
        | None -> List.rev acc
        | Some (a, x') -> unfold' x' (a::acc)
      unfold' x []
       
    let break p xs =
      let rec break' xs acc =
        match xs with
        | [] -> List.rev acc, []
        | x::_ when p x -> List.rev acc, xs
        | x::xs' -> break' xs' (x::acc)
      break' xs []

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems