FSharpVerbalExpressions


Tutorial: F# Verbal Expressions

The VerbalExpressions module includes the VerbEx type which wraps the familiar .NET RegEx in a type with useful functional members. Multiple constructors start with a regular expression in the constructor.

1: 
let verbEx = new VerbEx(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}")

Beyond this the module is an experimental DSL that allows you to compose regular expressions in natural language using the immutable VerbEx type. The remainder of this tutorial is concerned with the experimental DSL which is, frankly, not that practical.

For practical examples of using the core FsRegEx module for composability, see the following examples:

Verbal Expressions DSL

You can compose values of the VerbEx type with the |> operator, including creating a new regular expression by logical or on 2 existing VerbExs.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
#r "FsVerbalExpressions.dll"
open FsVerbalExpressions
open System.Text.RegularExpressions

let v =
    CommonVerbEx.Email
    |> VerbalExpression.verbExOrVerbEx RegexOptions.None CommonVerbEx.Url

let foundEmail =
    v
    |> VerbalExpression.isMatch "test@github.com"

let foundUrl =
    v
    |> VerbalExpression.isMatch "http://www.google.com"

printfn "%b" foundEmail
printfn "%b" foundUrl

// true
// true

Natural language composition consists of building up a new VerbEx from an old by functions which append special characters, groups, modifiers, and other attributes of the regular expression language.

function : 'T -> VerbEx -> VerbEx

See the API documentation for all the regular expression functions available.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
open VerbalExpression

let foundFromGithub =
    VerbEx()
    |> startOfLine
    |> something
    |> then' "github.com"
    |> endOfLine
    |> isMatch "test@github.com"

printfn "%b" foundFromGithub

// true

You do not have to worry about escaping special characters in your regular expression.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let foundSomethingSpecial =
    VerbEx()
    |> startOfLine
    |> something
    |> then' "*+?"
    |> anything
    |> isMatch "blah blah blah*+?yackety yack"

printfn "%b" foundSomethingSpecial

// true

Sometimes you may need more power than the natural language provides, or you just need to include a snippet of native regular expression. The add function lets you do that.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let foundSpecialInMultiline =
    VerbEx()
    |> add @"phrase1\*\+\?"
    |> anything
    |> isMatch @"phrase1*+?RestOfLine\n"
    
printfn "%b" foundSpecialInMultiline

// true

VerbExs posses all the power of the .Net RegEx class in a composable form.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
let n =
    VerbEx()
    |> word
    |> matches "three words here"

printfn "%i" n.Count

// 3

let betterFormat =
    VerbEx()
    |> add "\s+"
    |> or' "whitespace"
    |> replace "This     is   text with   far  too   much   whitespace" " "

printfn "%s" betterFormat

// This is text with far too much  

let groupName =  "GroupNumber"
 
VerbEx()
|> add "COD"
|> beginCaptureNamed groupName
|> any "0-9"
|> repeatPrevious 3
|> endCapture
|> then' "END"
|> capture "COD123END" groupName
|> printfn "%s"

// 123

VerbEx comes with first class support for unicode, including unicode general categories and .Net extension blocks.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
VerbEx()
|> beginCaptureNamed "upper"
|> unicodeCategory UniCodeGeneralCategory.LetterUppercase
|> add "+"
|> endCapture
|> capture "some mixed case WORDS" "upper"
|> printfn "%s"

// WORDS
val verbEx : obj

Full name: Tutorial.verbEx
namespace FsVerbalExpressions
namespace System
namespace System.Text
namespace System.Text.RegularExpressions
val v : VerbalExpression.VerbEx

Full name: Tutorial.v
module CommonVerbEx

from FsVerbalExpressions
val Email : VerbalExpression.VerbEx

Full name: FsVerbalExpressions.CommonVerbEx.Email
module VerbalExpression

from FsVerbalExpressions
val verbExOrVerbEx : regexOptions:RegexOptions -> verbEx:VerbalExpression.VerbEx -> verbEx:VerbalExpression.VerbEx -> VerbalExpression.VerbEx

Full name: FsVerbalExpressions.VerbalExpression.verbExOrVerbEx
type RegexOptions =
  | None = 0
  | IgnoreCase = 1
  | Multiline = 2
  | ExplicitCapture = 4
  | Compiled = 8
  | Singleline = 16
  | IgnorePatternWhitespace = 32
  | RightToLeft = 64
  | ECMAScript = 256
  | CultureInvariant = 512

Full name: System.Text.RegularExpressions.RegexOptions
field RegexOptions.None = 0
val Url : VerbalExpression.VerbEx

Full name: FsVerbalExpressions.CommonVerbEx.Url
val foundEmail : bool

Full name: Tutorial.foundEmail
val isMatch : value:string -> verbEx:VerbalExpression.VerbEx -> bool

Full name: FsVerbalExpressions.VerbalExpression.isMatch
val foundUrl : bool

Full name: Tutorial.foundUrl
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val foundFromGithub : bool

Full name: Tutorial.foundFromGithub
Multiple items
type VerbEx =
  new : unit -> VerbEx
  new : regularExpression:string -> VerbEx
  new : regexOptions:RegexOptions -> VerbEx
  new : regularExpression:string * regexOptions:RegexOptions -> VerbEx
  new : regularExpression:string * regexOptions:RegexOptions * matchTimeout:TimeSpan -> VerbEx
  member Capture : input:string -> string -> string
  member GroupNameFromNumber : n:int -> string option
  member GroupNames : unit -> string array
  member GroupNumberFromName : groupName:string -> int option
  member GroupNumbers : unit -> int array
  ...

Full name: FsVerbalExpressions.VerbalExpression.VerbEx

--------------------
new : unit -> VerbEx
new : regexOptions:RegexOptions -> VerbEx
new : regularExpression:string -> VerbEx
new : regularExpression:string * regexOptions:RegexOptions -> VerbEx
new : regularExpression:string * regexOptions:RegexOptions * matchTimeout:System.TimeSpan -> VerbEx
val startOfLine : verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.startOfLine
val something : verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.something
val then' : value:string -> verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.then'
val endOfLine : verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.endOfLine
val isMatch : value:string -> verbEx:VerbEx -> bool

Full name: FsVerbalExpressions.VerbalExpression.isMatch
val foundSomethingSpecial : bool

Full name: Tutorial.foundSomethingSpecial
val anything : verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.anything
val foundSpecialInMultiline : bool

Full name: Tutorial.foundSpecialInMultiline
val add : value:string -> verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.add
val n : FsMatch []

Full name: Tutorial.n
val word : verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.word
val matches : input:string -> verbEx:VerbEx -> FsMatch []

Full name: FsVerbalExpressions.VerbalExpression.matches
val betterFormat : string

Full name: Tutorial.betterFormat
val or' : regularExpression:string -> verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.or'
val replace : input:string -> replacement:string -> verbEx:VerbEx -> string

Full name: FsVerbalExpressions.VerbalExpression.replace
val groupName : string

Full name: Tutorial.groupName
val beginCaptureNamed : groupName:string -> verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.beginCaptureNamed
val any : value:string -> verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.any
val repeatPrevious : n:int -> VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.repeatPrevious
val endCapture : verbEx:VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.endCapture
val capture : input:string -> groupName:string -> verbEx:VerbEx -> string

Full name: FsVerbalExpressions.VerbalExpression.capture
val unicodeCategory : category:UniCodeGeneralCategory -> VerbEx -> VerbEx

Full name: FsVerbalExpressions.VerbalExpression.unicodeCategory
type UniCodeGeneralCategory =
  | LetterUppercase
  | LetterLowercase
  | LetterTitlecase
  | LetterModifier
  | LetterOther
  | Letter
  | MarkNonspacing
  | MarkSpacingCombining
  | MarkEnclosing
  | Mark
  ...
  override ToString : unit -> string

Full name: FsVerbalExpressions.UniCodeGeneralCategory
union case UniCodeGeneralCategory.LetterUppercase: UniCodeGeneralCategory
Fork me on GitHub