Seiten

Mittwoch, 15. September 2010

F# Finger Tree und RegEx. Teil 3.

Teil 1.
Teil 2.

Zurück zum eigentlichen Problem. Hier übrigens Online RegEx to Finite State Machine Tool.

#load @"..\fingertree.fsx"

open FData.FingerTree

let inline flip f b a= f a b

//Finite State Machine for Regex ".*(.*007.*).*"
let inline fsm i c =
match i, c with
|0, '(' -> 1
|0, _ -> 0
|1, '0' -> 2
|1, _ -> 1
|2, '0' -> 3
|2, _ -> 1
|3, '7' -> 4
|3, '0' -> 3
|3, _ -> 1
|4, ')' -> 5
|4, _ -> 4
|5, _ -> 5

let inline tabulate f = Array.init 6 (fun i-> f i)

//Table with tabulated function for each letter in our alphabet.
let letters =
[|' '..'z'|]
|>Array.map (fun i->i,tabulate (flip fsm i))
|>Map.ofArray

type Table= int []

type Size =
|Size of int

//product monoid.
type Monoid() =
interface IMonoid<Size * Table> with
member inline this.Zero = Size 0,tabulate id
member inline this.Plus a b =
match a,b with
|(Size a, ta), (Size b, tb) -> Size (a + b), tabulate (fun st -> tb.[ta.[st]] )


type Element =
|Elem of char
interface IMeasured<Size * Table> with
member inline this.Value =
match this with
|Elem a ->
Size 1, Map.find a letters

type FingerString =FingerTree<Element,Size * Table, Monoid>

let inline matches007 (s:FingerString) = (snd (measured s)).[0]=5

let inline fromList s=(s,Empty)||> List.foldBack (push_front<<Elem)

let inline insert i c tree =
let (l,r) = split (fun (Size n,_) -> n>i) tree
concat l (push_front (Elem c) r)

let inline replace i c tree =
update (fun (Size n,_) -> n>i) (Elem c) tree

let treeString : seq<char>->FingerString = fromList<<List.ofSeq
//Simulate an interactive loop
let loop l f tree=
let res = List.fold (fun acc (i,c)->
let result= f i c acc
result) tree l
printfn "with Loop. Result %A" (matches007 res)
res

//Tests
open System
open System.Text.RegularExpressions

let test f =
printfn "Test Start"
let sw = new System.Diagnostics.Stopwatch()
sw.Start()
f()
sw.Stop()
printfn "Time Duration : %A" sw.ElapsedMilliseconds

//Regex for test.
let regex = new Regex (".*\(.*007.*\).*")

//String with 100 000 chars.
let str = String.Concat( Array.create 10000 " Match Me " )

//List of strings for test.
let listString=[str; str + "(007)"; "(007" + str + ")"; "(007)" + str]

//List of finger trees for test.
let listFingerString = List.map treeString listString

let runTest ()=
List.fold (fun acc str->
test (fun ()->printfn "with Regex %A. Result %A " acc (regex.Match(str).Success))
acc+1) 0 listString|>ignore
List.fold (fun acc str->
test (fun ()->printfn "with Finger Tree %A. Result %A " acc (matches007 str))
acc+1) 0 listFingerString|>ignore

runTest ()

test (fun ()->loop [(3,'(');(4000,'u');(20005,'0');(20006,'0');(20007,'7');(20008,'r');(40009,')');(40010,' ');(11,'I')] insert stringTree|>ignore)

test (fun ()->loop [(3,'(');(4,'0');(5,'0');(6,'7');(8,')');(40010,' ');(11,'I')] insert stringTree|>ignore)

test (fun ()->loop [(40004,'(');(40005,'0');(40006,'0');(40007,'7');(40008,'r');(40009,')');(40010,' ');(11,'I')] insert stringTree|>ignore)

test (fun ()->loop [(3,'(');(4000,'u');(20005,'0');(20006,'0');(20007,'7');(20008,'r');(40009,')');(40010,' ');(11,'I')] replace stringTree|>ignore)

Keine Kommentare:

Kommentar veröffentlichen