Skip to content

Instantly share code, notes, and snippets.

@dburriss
Last active June 23, 2018 06:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dburriss/5407a37f08127679750a73e639665ab5 to your computer and use it in GitHub Desktop.
Save dburriss/5407a37f08127679750a73e639665ab5 to your computer and use it in GitHub Desktop.
A F# script file showing parsing text to a typed list. Run with `fsi.exe TextToList.fsx`
open System
type Type1 = {
val1:string
val2:string
}
type Type2 = {
val1:string
val2:string
}
type Aggregate =
| T1 of Type1
| T2 of Type2
type State =
| Start of Aggregate list
| Collecting of Aggregate list * string * (Map<string,string> -> Aggregate) * Map<string,string>
let lines = seq {
yield "BEGINTYPE1"
yield "VAL1: xxx"
yield "VAL2: yyy"
yield "ENDTYPE1"
yield "BEGINTYPE2"
yield "VAL1: xxx"
yield "VAL2: yyy"
yield "ENDTYPE2"
}
let mapType1 (dic:Map<string,string>) =
Aggregate.T1
{
val1 = dic.["VAL1"]
val2 = dic.["VAL2"]
}
let mapType2 (dic:Map<string,string>) =
Aggregate.T2
{
val1 = dic.["VAL1"]
val2 = dic.["VAL2"]
}
let (|Begin|_|) input =
match input with
| "BEGINTYPE1" -> Some ("TYPE1", mapType1)
| "BEGINTYPE2" -> Some ("TYPE2", mapType2)
| _ -> None
let (|Prop|_|) input =
if(String.IsNullOrEmpty(input:string)) then None
else
if(input.Contains(":")) then
let split = input.Split(':')
let pName = split.[0].Trim()
let pValue = split.[1].Trim()
Some (pName,pValue)
else None
let (|End|_|) (l,label,f,m) input =
match input with
| "ENDTYPE1" -> Some (List.append l ([f m]), label)
| "ENDTYPE2" -> Some (List.append l ([f m]), label)
| _ -> None
let folder state line =
match state with
| Start xs ->
match line with
| Begin (label, f) -> Collecting (xs, label, f, Map.empty<string,string>)
| _ -> failwithf "Should start with a BEGINTYPEx, intead was %s" line
| Collecting (xs, label, f, m) ->
match line with
| Prop (k,v) -> Collecting (xs, label, f, Map.add k v m)
| End(xs, label, f, m) (ys, s) -> Start ys
| _ -> failwithf "Expecting property or ENDTYPEx, instead was %s" line
let extractTypeList state =
match state with
| Start xs -> xs
| Collecting (xs, _,_,_) -> xs
let extractTypes lines =
lines
|> Seq.fold folder (Start [])
|> extractTypeList
let printTypes types =
types |> List.iter (fun a -> printfn "%A" a)
extractTypes lines
|> printTypes
@dburriss
Copy link
Author

Or as a console app:

open System

type Type1 = {
    val1:string
    val2:string
}

type Type2 = {
    val1:string
    val2:string
}

type Aggregate =
| T1 of Type1
| T2 of Type2

type State =
| Start of Aggregate list
| Collecting of Aggregate list * string * (Map<string,string> -> Aggregate) * Map<string,string>

[<EntryPoint>]
let main argv =

    let lines = seq {
            yield "BEGINTYPE1"
            yield "VAL1: xxx"
            yield "VAL2: yyy"
            yield "ENDTYPE1"
            yield "BEGINTYPE2"
            yield "VAL1: xxx"
            yield "VAL2: yyy"
            yield "ENDTYPE2"
        }

    let mapType1 (dic:Map<string,string>) = 
        Aggregate.T1 
            {
                val1 = dic.["VAL1"]
                val2 = dic.["VAL2"]
            }

    let mapType2 (dic:Map<string,string>) = 
        Aggregate.T2
            {
                val1 = dic.["VAL1"]
                val2 = dic.["VAL2"]
            }

    let (|Begin|_|) input =        
        match input with
            | "BEGINTYPE1" -> Some ("TYPE1", mapType1)
            | "BEGINTYPE2" -> Some ("TYPE2", mapType2)
            | _ -> None
    
    let (|Prop|_|) input =        
        if(String.IsNullOrEmpty(input)) then None
        else 
            if(input.Contains(":")) then
                let split = input.Split(":")
                let pName = split.[0].Trim()
                let pValue = split.[1].Trim()
                Some (pName,pValue)
            else None

    let (|End|_|) (l,label,f,m) input =        
        match input with
            | "ENDTYPE1" -> Some (List.append l ([f m]), label)
            | "ENDTYPE2" -> Some (List.append l ([f m]), label)
            | _ -> None

    let folder state line =
        match state with
        | Start xs -> 
            match line with
            | Begin (label, f) -> Collecting (xs, label, f, Map.empty<string,string>)
            | _ -> failwithf "Should start with a BEGINTYPEx, intead was %s" line
        | Collecting (xs, label, f, m) -> 
            match line with
            | Prop (k,v) -> Collecting (xs, label, f, Map.add k v m)
            | End(xs, label, f, m) (ys, s) -> Start ys
            | _ -> failwithf "Expecting property or ENDTYPEx, instead was %s" line
        
    let extractTypeList state =
        match state with
        | Start xs -> xs
        | Collecting (xs, _,_,_) -> xs

    let extractTypes lines = 
        lines 
        |> Seq.fold folder (Start [])
        |> extractTypeList
        |> List.iter (fun a -> printfn "%A" a)

    extractTypes lines |> ignore

    Console.ReadKey() |> ignore

    0 // return an integer exit code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment