text:
module VerbalExpressions

open FsRegEx
open System.Text.RegularExpressions

let firstMatch input (fsRegEx : FsRegEx) =
    fsRegEx .Match input

let matchAt input startAt (fsRegEx : FsRegEx) =
    fsRegEx .Match (input, startAt)

let matches input (fsRegEx : FsRegEx) =
    fsRegEx .Matches input

let matchesAt input startAt (fsRegEx : FsRegEx) =
    fsRegEx .Matches (input, startAt)

let matchAtFor input startAt length (fsRegEx : FsRegEx) =
    fsRegEx .Match (input, startAt, length)

let replace input (replacement : string) (fsRegEx : FsRegEx) =
    fsRegEx .Replace(input, replacement)

let replaceByMatch input (evalutor : MatchEvaluator) (fsRegEx : FsRegEx) =
    fsRegEx .Replace(input, evalutor)

let replaceMaxTimes input (replacement : string) count (fsRegEx : FsRegEx) =
    fsRegEx .Replace(input, replacement, count )

let replaceByMatchMaxTimes input (evalutor : MatchEvaluator) count (fsRegEx : FsRegEx) =
    fsRegEx .Replace(input, evalutor, count)

let replaceMaxTimesStartAt input (replacement : string) count startAt (fsRegEx : FsRegEx) =
    fsRegEx .Replace(input, replacement, count, startAt)

let replaceByMatchMaxTimesStartAt input (evalutor : MatchEvaluator) count startAt (fsRegEx : FsRegEx) =
    fsRegEx .Replace(input, evalutor, count, startAt)

let split input (fsRegEx : FsRegEx) =
    fsRegEx .Split input

let splitMaxTimes input count (fsRegEx : FsRegEx) =
    fsRegEx .Split (input, count)

let splitMaxTimesStartAt input count startAt (fsRegEx : FsRegEx) =
    fsRegEx .Split (input, count, startAt)

let resetRegexOptions regexOptions (fsRegEx : FsRegEx) =
    fsRegEx .Clone regexOptions

let capture input groupName (fsRegEx : FsRegEx) =
    fsRegEx .Capture input groupName

let groupNames (fsRegEx : FsRegEx) =
    fsRegEx .GroupNames()

let groupNumbers (fsRegEx : FsRegEx) =
    fsRegEx .GroupNumbers()

let isMatch value (fsRegEx : FsRegEx) =
    fsRegEx .IsMatch value

let isMatchAt value startAt (fsRegEx : FsRegEx) =
    fsRegEx .IsMatch (value, startAt)

let toString (fsRegEx : FsRegEx) =
    fsRegEx .ToString()

let startOfLine (fsRegEx : FsRegEx) =
    let v = fsRegEx .Clone None
    if v.Prefixes.StartsWith("^") then v
    else
        v.Prefixes <- "^" + v.Prefixes
        v

let endOfLine (fsRegEx : FsRegEx) =
    let v = fsRegEx .Clone None
    if v.Suffixes.EndsWith("$") then v
    else
        v.Suffixes <- v.Suffixes + "$"
        v

let add value (fsRegEx : FsRegEx) =
    let v = fsRegEx .Clone None
    v.Source <- v.Source + value
    v

let internalAdd (fsRegEx : FsRegEx) value =
    let v = fsRegEx .Clone None
    v.Source <- v.Source + value
    v

let then' value (fsRegEx : FsRegEx) =
    Regex.Escape value
    |> sprintf "(%s)"
    |> internalAdd fsRegEx

let find value (fsRegEx : FsRegEx) = then' value fsRegEx

let maybe value (fsRegEx : FsRegEx) =
    Regex.Escape value
    |> sprintf "(%s)?"
    |> internalAdd fsRegEx

let anything (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  "(.*)"

let anythingBut value (fsRegEx : FsRegEx) =
    Regex.Escape value
    |> sprintf "([^%s]*)"
    |> internalAdd fsRegEx

let something (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  "(.+)"

let somethingBut value (fsRegEx : FsRegEx) =
    Regex.Escape value
    |> sprintf "([^%s]+)"
    |> internalAdd fsRegEx

let lineBreak (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"(\n|(\r\n))"

let br (fsRegEx : FsRegEx) = lineBreak fsRegEx

let tab (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\t"

let whiteSpace (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\s"

let nonWhiteSpace (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\S"

let word (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\w+"

let wordCharacter (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\w"

let nonWordCharacter (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\W"

let digit (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\d"

let nonDigit (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  @"\D"

let backReference ordinal (fsRegEx : FsRegEx) =
    if ordinal < 1 then invalidArg "ordinal" "must be greater than 0"

    sprintf @"\%i" ordinal
    |> internalAdd fsRegEx

let namedBackReference name (fsRegEx : FsRegEx) =
    sprintf @"\k<%s>" name
    |> internalAdd fsRegEx

let anyOf value (fsRegEx : FsRegEx) =
    Regex.Escape value
    |> sprintf "[%s]"
    |> internalAdd fsRegEx

let any value (fsRegEx : FsRegEx) = anyOf value fsRegEx

let range (collection : seq<obj>) (fsRegEx : FsRegEx) =

    let elem =
        collection
        |> Seq.fold (fun s t ->
            let x = t.ToString()
            if x.Length = 0 then s
            else Regex.Escape(x)::s) []
        |> List.rev

    let divisor =
        if elem.Length % 2 = 0 then
            elem.Length / 2
        else
            elem.Length / 2 + 1

    List.splitInto divisor elem
    |> List.fold (fun (s : string) t ->
        if t.Length = 1 then
            if s.Length = 0 then
                invalidArg "range" "one-element range"
            else
                s + "|" + t.Head
        else
            s + ("[" + t.Head + "-" + t.Tail.Head + "]") ) ""
    |> internalAdd fsRegEx

let multiple value (fsRegEx : FsRegEx) =
    Regex.Escape value
    |> sprintf @"(%s)+"
    |> internalAdd fsRegEx

let multipleFsRegEx (sourceFsRegEx : FsRegEx) (fsRegEx : FsRegEx) =
    sourceFsRegEx.ToString()
    |> sprintf @"(%s)+"
    |> internalAdd fsRegEx

let or' value (fsRegEx : FsRegEx) =
    let v = fsRegEx .Clone None
    if v.Source.EndsWith("(") || v.Source.EndsWith(">") then //begin capture
        v.Source <- v.Source + value
    else
        if v.Prefixes.Length > 0 || v.Source.Length > 0 then
            v.Source <- v.Source + "|" + value
        else
            v.Source <- value
    v

let fsRegExOrFsRegEx regexOptions (fsRegEx : FsRegEx) (fsRegEx2 : FsRegEx) =
    let v = fsRegEx .Clone (Some regexOptions)
    v.Prefixes <- v.Prefixes + "("
    v.Source <- v.Source + ")|(" + fsRegEx2.ToString()
    v.Suffixes <- ")" + v.Suffixes
    v

let beginCapture (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  "("

let beginCaptureNamed groupName (fsRegEx : FsRegEx) =
    Regex.Escape groupName
    |> sprintf "(?<%s>"
    |> internalAdd fsRegEx

let endCapture (fsRegEx : FsRegEx) =
    internalAdd fsRegEx  ")"

let repeatPrevious n (fsRegEx : FsRegEx) =

    if n < 1 then
        invalidArg "repeatPrevious" "must be greater than 0"

    sprintf "{%i}" n
    |> internalAdd fsRegEx

let repeatBetweenPrevious n m (fsRegEx : FsRegEx) =

    if n < 1 then
        invalidArg "repeatBetweenPrevious" "must be greater than 0"

    if n >= m then
        invalidArg "repeatBetweenPrevious" "m must be greater than n"

    sprintf "{%i,%i}" n m
    |> internalAdd fsRegEx

let unicode  nnnn (fsRegEx : FsRegEx) =

    sprintf "\u%s" nnnn
    |> internalAdd fsRegEx

let unicodeCategory (category : Unicode.UnicodeGeneralCategory) (fsRegEx : FsRegEx) =

    category.ToString()
    |> sprintf "\p{%s}"
    |> internalAdd fsRegEx

let notUnicodeCategory (category : Unicode.UnicodeGeneralCategory) (fsRegEx : FsRegEx) =

    category.ToString()
    |> sprintf "\P{%s}"
    |> internalAdd fsRegEx

let namedBlock (name : Unicode.SupportedNamedBlock) (fsRegEx : FsRegEx) =

    name.ToString()
    |> sprintf "\p{%s}"
    |> internalAdd fsRegEx

let notNamedBlock (name : Unicode.SupportedNamedBlock) (fsRegEx : FsRegEx) =

    name.ToString()
    |> sprintf "\P{%s}"
    |> internalAdd fsRegEx

let iter (f : (FsRegEx -> unit)) (fsRegEx : FsRegEx)  : unit = f fsRegEx

let map (f : (FsRegEx -> FsRegEx)) fsRegEx  = f fsRegEx

let fold (f : ('State -> FsRegEx -> 'State)) state fsRegEx  = f state fsRegEx

let foldBack (f : (FsRegEx -> 'State -> 'State)) fsRegEx  state = f fsRegEx  state

let exists (f : (FsRegEx -> bool)) fsRegEx  = f fsRegEx


text:
// Auto-Generated by FAKE; do not edit
namespace System
open System.Reflection

[<assembly: AssemblyTitleAttribute("FsRegEx")>]
[<assembly: AssemblyProductAttribute("FsRegEx")>]
[<assembly: AssemblyDescriptionAttribute("Composable F# regular expressions.")>]
[<assembly: AssemblyVersionAttribute("0.7.2")>]
[<assembly: AssemblyFileVersionAttribute("0.7.2")>]
[<assembly: AssemblyConfigurationAttribute("Release")>]
do ()

module internal AssemblyVersionInformation =
    let [<Literal>] AssemblyTitle = "FsRegEx"
    let [<Literal>] AssemblyProduct = "FsRegEx"
    let [<Literal>] AssemblyDescription = "Composable F# regular expressions."
    let [<Literal>] AssemblyVersion = "0.7.2"
    let [<Literal>] AssemblyFileVersion = "0.7.2"
    let [<Literal>] AssemblyConfiguration = "Release"

repo_name: jackfoxy/FsRegEx

repo_language: F#

mime_type: text/plain


text:
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
    <RootNamespace>FsRegEx</RootNamespace>
    <AssemblyName>FsRegEx</AssemblyName>
    <Name>FsRegEx</Name>
    <OutputType>Library</OutputType>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <!-- Optional: Declare that the Repository URL can be published to NuSpec -->
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <!-- Optional: Embed source files that are not tracked by the source control manager to the PDB -->
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
    <!-- Optional: Include PDB in the built .nupkg -->
    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="FsRegEx.fsi" />
    <Compile Include="FsRegEx.fs" />
    <Compile Include="VerbalExpressions.fsi" />
    <Compile Include="VerbalExpressions.fs" />
    <Compile Include="CommonFsRegEx.fsi" />
    <Compile Include="CommonFsRegEx.fs" />
    <None Include="paket.references" />
    <None Include="paket.template" />
    <None Include="Scripts\CompileToAssembly.fsx" />
    <None Include="Scripts\Escape.fsx" />
    <None Include="Scripts\GetGroupNames.fsx" />
    <None Include="Scripts\GetGroupNumbers.fsx" />
    <None Include="Scripts\Group.fsx" />
    <None Include="Scripts\GroupCollection.fsx" />
    <None Include="Scripts\GroupNameFromNumber.fsx" />
    <None Include="Scripts\IsMatch.fsx" />
    <None Include="Scripts\load-project-debug.fsx" />
    <None Include="Scripts\load-project-release.fsx" />
    <None Include="Scripts\load-references-debug.fsx" />
    <None Include="Scripts\load-references-release.fsx" />
    <None Include="Scripts\Match.fsx" />
    <None Include="Scripts\Matches.fsx" />
    <None Include="Scripts\MatchTimeout.fsx" />
    <None Include="Scripts\Replace.fsx" />
    <None Include="Scripts\Script1.fsx" />
    <None Include="Scripts\Split.fsx" />
  </ItemGroup>
  <Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>


text:
module FsRegEx

open System
open System.Text.RegularExpressions
open System.Threading

module Unicode =
    ///Enum Unicode defined general categories
    type UnicodeGeneralCategory =
        ///Letter, Uppercase; Lu
        | LetterUppercase
        ///Letter, Lowercase; Ll
        | LetterLowercase
        ///Letter, Titlecase; Lt
        | LetterTitlecase
        ///Letter, Modifier; Lm
        | LetterModifier
        ///Letter, Other; Lo
        | LetterOther
        ///All letter characters. This includes the LetterUppercase, LetterLowercase, LetterTitlecase, LetterModifier, and LetterOther characters; L
        | Letter
        ///Mark, Nonspacing; Mn
        | MarkNonspacing
        ///Mark, Spacing Combining; Mc
        | MarkSpacingCombining
        ///Mark, Enclosing; Me
        | MarkEnclosing
        ///All diacritic marks. This includes the MarkNonspacing, MarkSpacingCombining, and MarkEnclosing categories; M
        | Mark
        ///Number, Decimal Digit; Nd
        | NumberDecimalDigit
        ///Number, Letter; Nl
        | NumberLetter
        ///Number, Other; No
        | NumberOther
        ///All numbers. This includes the Nd, Nl, and No categories; N
        | NumberALL
        ///Punctuation, Connector; Pc
        | PunctuationConnector
        ///Punctuation, Dash; Pd
        | PunctuationDash
        ///Punctuation, Open; Ps
        | PunctuationOpen
        ///Punctuation, Close; Pe
        | PunctuationClose
        ///Punctuation, Initial quote (may behave like Ps or Pe depending on usage); Pi
        | PunctuationInitial
        ///Punctuation, Final quote (may behave like Ps or Pe depending on usage); Pf
        | PunctuationFinal
        ///Punctuation, Other; Po
        | PunctuationOther
        ///All punctuation characters. This includes the PunctuationConnector, PunctuationDash, PunctuationOpen, PunctuationClose, PunctuationInitial, PunctuationFinal, and PunctuationOther categories; P
        | Punctuation
        ///Symbol, Math; Sm
        | SymbolMath
        ///Symbol, Currency; Sc
        | SymbolCurrency
        ///Symbol, Modifier; Sk
        | SymbolModifier
        ///Symbol, Other; So
        | SymbolOther
        ///All symbols. This includes the SymbolMath, SymbolCurrency, SymbolModifier, and SymbolOther categories; S
        | Symbol
        ///Separator, Space; Zs
        | SeparatorSpace
        ///Separator, Line; Zl
        | SeparatorLine
        ///Separator, Paragraph; Zp
        | SeparatorParagraph
        ///All separator characters. This includes the SeparatorSpace, SeparatorLine, and SeparatorLine categories; Z
        | Separator
        ///Other, Control; Cc
        | OtherControl
        ///Other, Format; Cf
        | OtherFormat
        ///Other, Surrogate; Cs
        | OtherSurrogate
        ///Other, Private Use; Co
        | OtherPrivateUse
        ///Other, Not Assigned (no characters have this property); Cn
        | OtherNotAssigned
        ///All control characters. This includes the OtherControl, OtherFormat, OtherSurrogate, OtherPrivateUse, and OtherNotAssigned categories; C
        | ControlAll
        override __.ToString() =
            match __ with
            | LetterUppercase -> "Lu"
            | LetterLowercase -> "Ll"
            | LetterTitlecase -> "Lt"
            | LetterModifier -> "Lm"
            | LetterOther -> "Lo"
            | Letter -> "L"
            | MarkNonspacing -> "Mn"
            | MarkSpacingCombining -> "Mc"
            | MarkEnclosing -> "Me"
            | Mark -> "M"
            | NumberDecimalDigit -> "Nd"
            | NumberLetter -> "Nl"
            | NumberOther -> "No"
            | NumberALL -> "N"
            | PunctuationConnector -> "Pc"
            | PunctuationDash -> "Pd"
            | PunctuationOpen -> "Ps"
            | PunctuationClose -> "Pe"
            | PunctuationInitial -> "Pi"
            | PunctuationFinal -> "Pf"
            | PunctuationOther -> "Po"
            | Punctuation -> "P"
            | SymbolMath -> "Sm"
            | SymbolCurrency -> "Sc"
            | SymbolModifier -> "Sk"
            | SymbolOther -> "So"
            | Symbol -> "S"
            | SeparatorSpace -> "Zs"
            | SeparatorLine -> "Zl"
            | SeparatorParagraph -> "Zp"
            | Separator -> "Z"
            | OtherControl -> "Cc"
            | OtherFormat -> "Cf"
            | OtherSurrogate -> "Cs"
            | OtherPrivateUse -> "Co"
            | OtherNotAssigned -> "Cn"
            | ControlAll -> "C"

    ///Enum .NET Framework named Unicode blocks
    type SupportedNamedBlock =
        ///0000 - 007F
        | IsBasicLatin
        ///0080 - 00FF
        | IsLatin1Supplement
        ///0100 - 017F
        | IsLatinExtendedA
        ///0180 - 024F
        | IsLatinExtendedB
        ///0250 - 02AF
        | IsIPAExtensions
        ///02B0 - 02FF
        | IsSpacingModifierLetters
        ///0300 - 036F
        | IsCombiningDiacriticalMarks
        ///0370 - 03FF
        | IsGreek
        ///0370 - 03FF
        | IsGreekandCoptic
        ///0400 - 04FF
        | IsCyrillic
        ///0500 - 052F
        | IsCyrillicSupplement
        ///0530 - 058F
        | IsArmenian
        ///0590 - 05FF
        | IsHebrew
        ///0600 - 06FF
        | IsArabic
        ///0700 - 074F
        | IsSyriac
        ///0780 - 07BF
        | IsThaana
        ///0900 - 097F
        | IsDevanagari
        ///0980 - 09FF
        | IsBengali
        ///0A00 - 0A7F
        | IsGurmukhi
        ///0A80 - 0AFF
        | IsGujarati
        ///0B00 - 0B7F
        | IsOriya
        ///0B80 - 0BFF
        | IsTamil
        ///0C00 - 0C7F
        | IsTelugu
        ///0C80 - 0CFF
        | IsKannada
        ///0D00 - 0D7F
        | IsMalayalam
        ///0D80 - 0DFF
        | IsSinhala
        ///0E00 - 0E7F
        | IsThai
        ///0E80 - 0EFF
        | IsLao
        ///0F00 - 0FFF
        | IsTibetan
        ///1000 - 109F
        | IsMyanmar
        ///10A0 - 10FF
        | IsGeorgian
        ///1100 - 11FF
        | IsHangulJamo
        ///1200 - 137F
        | IsEthiopic
        ///13A0 - 13FF
        | IsCherokee
        ///1400 - 167F
        | IsUnifiedCanadianAboriginalSyllabics
        ///1680 - 169F
        | IsOgham
        ///16A0 - 16FF
        | IsRunic
        ///1700 - 171F
        | IsTagalog
        ///1720 - 173F
        | IsHanunoo
        ///1740 - 175F
        | IsBuhid
        ///1760 - 177F
        | IsTagbanwa
        ///1780 - 17FF
        | IsKhmer
        ///1800 - 18AF
        | IsMongolian
        ///1900 - 194F
        | IsLimbu
        ///1950 - 197F
        | IsTaiLe
        ///19E0 - 19FF
        | IsKhmerSymbols
        ///1D00 - 1D7F
        | IsPhoneticExtensions
        ///1E00 - 1EFF
        | IsLatinExtendedAdditional
        ///1F00 - 1FFF
        | IsGreekExtended
        ///2000 - 206F
        | IsGeneralPunctuation
        ///2070 - 209F
        | IsSuperscriptsandSubscripts
        ///20A0 - 20CF
        | IsCurrencySymbols
        ///20D0 - 20FF
        | IsCombiningDiacriticalMarksforSymbols
        ///20D0 - 20FF
        | IsCombiningMarksforSymbols
        ///2100 - 214F
        | IsLetterlikeSymbols
        ///2150 - 218F
        | IsNumberForms
        ///2190 - 21FF
        | IsArrows
        ///2200 - 22FF
        | IsMathematicalOperators
        ///2300 - 23FF
        | IsMiscellaneousTechnical
        ///2400 - 243F
        | IsControlPictures
        ///2440 - 245F
        | IsOpticalCharacterRecognition
        ///2460 - 24FF
        | IsEnclosedAlphanumerics
        ///2500 - 257F
        | IsBoxDrawing
        ///2580 - 259F
        | IsBlockElements
        ///25A0 - 25FF
        | IsGeometricShapes
        ///2600 - 26FF
        | IsMiscellaneousSymbols
        ///2700 - 27BF
        | IsDingbats
        ///27C0 - 27EF
        | IsMiscellaneousMathematicalSymbolsA
        ///27F0 - 27FF
        | IsSupplementalArrowsA
        ///2800 - 28FF
        | IsBraillePatterns
        ///2900 - 297F
        | IsSupplementalArrowsB
        ///2980 - 29FF
        | IsMiscellaneousMathematicalSymbolsB
        ///2A00 - 2AFF
        | IsSupplementalMathematicalOperators
        ///2B00 - 2BFF
        | IsMiscellaneousSymbolsandArrows
        ///2E80 - 2EFF
        | IsCJKRadicalsSupplement
        ///2F00 - 2FDF
        | IsKangxiRadicals
        ///2FF0 - 2FFF
        | IsIdeographicDescriptionCharacters
        ///3000 - 303F
        | IsCJKSymbolsandPunctuation
        ///3040 - 309F
        | IsHiragana
        ///30A0 - 30FF
        | IsKatakana
        ///3100 - 312F
        | IsBopomofo
        ///3130 - 318F
        | IsHangulCompatibilityJamo
        ///3190 - 319F
        | IsKanbun
        ///31A0 - 31BF
        | IsBopomofoExtended
        ///31F0 - 31FF
        | IsKatakanaPhoneticExtensions
        ///3200 - 32FF
        | IsEnclosedCJKLettersandMonths
        ///3300 - 33FF
        | IsCJKCompatibility
        ///3400 - 4DBF
        | IsCJKUnifiedIdeographsExtensionA
        ///4DC0 - 4DFF
        | IsYijingHexagramSymbols
        ///4E00 - 9FFF
        | IsCJKUnifiedIdeographs
        ///A000 - A48F
        | IsYiSyllables
        ///A490 - A4CF
        | IsYiRadicals
        ///AC00 - D7AF
        | IsHangulSyllables
        ///D800 - DB7F
        | IsHighSurrogates
        ///DB80 - DBFF
        | IsHighPrivateUseSurrogates
        ///DC00 - DFFF
        | IsLowSurrogates
        ///E000 - F8FF
        | IsPrivateUse
        ///F900 - FAFF
        | IsCJKCompatibilityIdeographs
        ///FB00 - FB4F
        | IsAlphabeticPresentationForms
        ///FB50 - FDFF
        | IsArabicPresentationFormsA
        ///FE00 - FE0F
        | IsVariationSelectors
        ///FE20 - FE2F
        | IsCombiningHalfMarks
        ///FE30 - FE4F
        | IsCJKCompatibilityForms
        ///FE50 - FE6F
        | IsSmallFormVariants
        ///FE70 - FEFF
        | IsArabicPresentationFormsB
        ///FF00 - FFEF
        | IsHalfwidthandFullwidthForms
        ///FFF0 - FFFF
        | IsSpecials
        override __.ToString() =
            match __ with
            | IsBasicLatin -> "IsBasicLatin"
            | IsLatin1Supplement -> "IsLatin-1Supplement"
            | IsLatinExtendedA -> "IsLatinExtended-A"
            | IsLatinExtendedB -> "IsLatinExtended-B"
            | IsIPAExtensions -> "IsIPAExtensions"
            | IsSpacingModifierLetters -> "IsSpacingModifierLetters"
            | IsCombiningDiacriticalMarks -> "IsCombiningDiacriticalMarks"
            | IsGreek -> "IsGreek"
            | IsGreekandCoptic -> "IsGreekandCoptic"
            | IsCyrillic -> "IsCyrillic"
            | IsCyrillicSupplement -> "IsCyrillicSupplement"
            | IsArmenian -> "IsArmenian"
            | IsHebrew -> "IsHebrew"
            | IsArabic -> "IsArabic"
            | IsSyriac -> "IsSyriac"
            | IsThaana -> "IsThaana"
            | IsDevanagari -> "IsDevanagari"
            | IsBengali -> "IsBengali"
            | IsGurmukhi -> "IsGurmukhi"
            | IsGujarati -> "IsGujarati"
            | IsOriya -> "IsOriya"
            | IsTamil -> "IsTamil"
            | IsTelugu -> "IsTelugu"
            | IsKannada -> "IsKannada"
            | IsMalayalam -> "IsMalayalam"
            | IsSinhala -> "IsSinhala"
            | IsThai -> "IsThai"
            | IsLao -> "IsLao"
            | IsTibetan -> "IsTibetan"
            | IsMyanmar -> "IsMyanmar"
            | IsGeorgian -> "IsGeorgian"
            | IsHangulJamo -> "IsHangulJamo"
            | IsEthiopic -> "IsEthiopic"
            | IsCherokee -> "IsCherokee"
            | IsUnifiedCanadianAboriginalSyllabics -> "IsUnifiedCanadianAboriginalSyllabics"
            | IsOgham -> "IsOgham"
            | IsRunic -> "IsRunic"
            | IsTagalog -> "IsTagalog"
            | IsHanunoo -> "IsHanunoo"
            | IsBuhid -> "IsBuhid"
            | IsTagbanwa -> "IsTagbanwa"
            | IsKhmer -> "IsKhmer"
            | IsMongolian -> "IsMongolian"
            | IsLimbu -> "IsLimbu"
            | IsTaiLe -> "IsTaiLe"
            | IsKhmerSymbols -> "IsKhmerSymbols"
            | IsPhoneticExtensions -> "IsPhoneticExtensions"
            | IsLatinExtendedAdditional -> "IsLatinExtendedAdditional"
            | IsGreekExtended -> "IsGreekExtended"
            | IsGeneralPunctuation -> "IsGeneralPunctuation"
            | IsSuperscriptsandSubscripts -> "IsSuperscriptsandSubscripts"
            | IsCurrencySymbols -> "IsCurrencySymbols"
            | IsCombiningDiacriticalMarksforSymbols -> "IsCombiningDiacriticalMarksforSymbols"
            | IsCombiningMarksforSymbols -> "IsCombiningMarksforSymbols"
            | IsLetterlikeSymbols -> "IsLetterlikeSymbols"
            | IsNumberForms -> "IsNumberForms"
            | IsArrows -> "IsArrows"
            | IsMathematicalOperators -> "IsMathematicalOperators"
            | IsMiscellaneousTechnical -> "IsMiscellaneousTechnical"
            | IsControlPictures -> "IsControlPictures"
            | IsOpticalCharacterRecognition -> "IsOpticalCharacterRecognition"
            | IsEnclosedAlphanumerics -> "IsEnclosedAlphanumerics"
            | IsBoxDrawing -> "IsBoxDrawing"
            | IsBlockElements -> "IsBlockElements"
            | IsGeometricShapes -> "IsGeometricShapes"
            | IsMiscellaneousSymbols -> "IsMiscellaneousSymbols"
            | IsDingbats -> "IsDingbats"
            | IsMiscellaneousMathematicalSymbolsA -> "IsMiscellaneousMathematicalSymbols-A"
            | IsSupplementalArrowsA -> "IsSupplementalArrows-A"
            | IsBraillePatterns -> "IsBraillePatterns"
            | IsSupplementalArrowsB -> "IsSupplementalArrows-B"
            | IsMiscellaneousMathematicalSymbolsB -> "IsMiscellaneousMathematicalSymbols-B"
            | IsSupplementalMathematicalOperators -> "IsSupplementalMathematicalOperators"
            | IsMiscellaneousSymbolsandArrows -> "IsMiscellaneousSymbolsandArrows"
            | IsCJKRadicalsSupplement -> "IsCJKRadicalsSupplement"
            | IsKangxiRadicals -> "IsKangxiRadicals"
            | IsIdeographicDescriptionCharacters -> "IsIdeographicDescriptionCharacters"
            | IsCJKSymbolsandPunctuation -> "IsCJKSymbolsandPunctuation"
            | IsHiragana -> "IsHiragana"
            | IsKatakana -> "IsKatakana"
            | IsBopomofo -> "IsBopomofo"
            | IsHangulCompatibilityJamo -> "IsHangulCompatibilityJamo"
            | IsKanbun -> "IsKanbun"
            | IsBopomofoExtended -> "IsBopomofoExtended"
            | IsKatakanaPhoneticExtensions -> "IsKatakanaPhoneticExtensions"
            | IsEnclosedCJKLettersandMonths -> "IsEnclosedCJKLettersandMonths"
            | IsCJKCompatibility -> "IsCJKCompatibility"
            | IsCJKUnifiedIdeographsExtensionA -> "IsCJKUnifiedIdeographsExtensionA"
            | IsYijingHexagramSymbols -> "IsYijingHexagramSymbols"
            | IsCJKUnifiedIdeographs -> "IsCJKUnifiedIdeographs"
            | IsYiSyllables -> "IsYiSyllables"
            | IsYiRadicals -> "IsYiRadicals"
            | IsHangulSyllables -> "IsHangulSyllables"
            | IsHighSurrogates -> "IsHighSurrogates"
            | IsHighPrivateUseSurrogates -> "IsHighPrivateUseSurrogates"
            | IsLowSurrogates -> "IsLowSurrogates"
            | IsPrivateUse -> "IsPrivateUse"
            | IsCJKCompatibilityIdeographs  -> "IsCJKCompatibilityIdeographs "
            | IsAlphabeticPresentationForms  -> "IsAlphabeticPresentationForms "
            | IsArabicPresentationFormsA  -> "IsArabicPresentationForms-A "
            | IsVariationSelectors  -> "IsVariationSelectors "
            | IsCombiningHalfMarks  -> "IsCombiningHalfMarks "
            | IsCJKCompatibilityForms  -> "IsCJKCompatibilityForms "
            | IsSmallFormVariants  -> "IsSmallFormVariants "
            | IsArabicPresentationFormsB  -> "IsArabicPresentationForms-B "
            | IsHalfwidthandFullwidthForms  -> "IsHalfwidthandFullwidthForms "
            | IsSpecials -> "IsSpecials"

type FsGroup (name : string, group : Group) =
    let mutable captures : Capture [] option = None
    override __.Equals(yobj) =

        match yobj with
        | :? FsGroup as y -> (group = y.Group)
        | _ -> false
    override __.GetHashCode() = group.GetHashCode()
    override __.ToString() = group.ToString()
    member __.Captures() =
        match captures with
        | Some x -> x
        | None ->
            let a : Capture[] = Array.zeroCreate group.Captures.Count
            group.Captures.CopyTo(a, 0)
            captures <- Some a
            a
    member __.Group = group
    member __.Index =
        group.Index
    member __.Length =
        group.Length
    member ___.Name = name
    member __.Success =
        group.Success
    member __.Value =
        group.Value

type FsMatch (regex : Regex, fsMatch : Match) =
    override __.Equals(yobj) =

        match yobj with
        | :? FsMatch as y -> (fsMatch = y.Match)
        | _ -> false
    override __.GetHashCode() = fsMatch.GetHashCode()
    override __.ToString() = fsMatch.ToString()
    member __.Captures() =

        let a : Capture[] = Array.zeroCreate fsMatch.Captures.Count
        fsMatch.Captures.CopyTo(a, 0)
        a
    member __.Groups() =
        let a : Group[] = Array.zeroCreate fsMatch.Groups.Count
        fsMatch.Groups.CopyTo(a, 0)
        a
        |> Array.mapi (fun i t -> FsGroup(regex.GroupNameFromNumber(i), t))
    member __.Index =
        fsMatch.Index
    member __.Length =
        fsMatch.Length
    member __.Match = fsMatch
    member __.Result replacement =
        fsMatch.Result replacement
    member __.Success =
        fsMatch.Success
    member __.Value =
        fsMatch.Value

module internal Common =

    let arrayFromMatches regex (c : MatchCollection) =
        let a : Match[] = Array.zeroCreate c.Count
        c.CopyTo(a, 0)
        a
        |> Array.map (fun t -> new FsMatch(regex, t))

type FsRegEx(regularExpression : string, regexOptions : RegexOptions, matchTimeout : TimeSpan) =
    let mutable _matchTimeout = matchTimeout
    let mutable _regexOptions : RegexOptions = regexOptions
    let mutable _prefixes = ""
    let mutable _source = regularExpression
    let mutable _suffixes = ""
    let mutable _regex : Regex option = None

    override __.Equals(yobj) =
        match yobj with
        | :? FsRegEx as y -> (__.GetHashCode() = y.GetHashCode())
        | _ -> false

    override __.GetHashCode() =
        _regexOptions.GetHashCode().ToString() + __.ToString()
        |> hash

    override __.ToString() = _prefixes + _source + _suffixes

    new () =
        FsRegEx("", RegexOptions.None, Timeout.InfiniteTimeSpan)

    new (regexOptions : RegexOptions) =
        FsRegEx("", regexOptions, Timeout.InfiniteTimeSpan)

    new (regularExpression : string) =
        FsRegEx(regularExpression, RegexOptions.None, Timeout.InfiniteTimeSpan)

    new (regularExpression : string, regexOptions : RegexOptions) =
        FsRegEx(regularExpression, regexOptions, Timeout.InfiniteTimeSpan)

    member __.Regex =
        match _regex with
        | Some x -> x
        | None ->
            let regex = new Regex(__.ToString(), _regexOptions, _matchTimeout)

            _regex <- Some regex
            regex

    member __.Capture input (groupName : string) =
        let match' = __.Regex.Match input
        match'.Groups.[groupName].Value

    member __.Clone (newRegexOptions : RegexOptions option) =
        let v =
            match newRegexOptions with
            | Some x -> new FsRegEx(x)
            | None -> new FsRegEx(_regexOptions)

        v.Prefixes <- _prefixes
        v.Source <- _source
        v.Suffixes <- _suffixes
        v

    member __.GroupNameFromNumber n =
        let name =
            __.Regex.GroupNameFromNumber n

        if String.IsNullOrEmpty name then None
        else Some name

    member __.GroupNames() =
        __.Regex.GetGroupNames()

    member __.GroupNumberFromName groupName =
        let n =
            __.Regex.GroupNumberFromName groupName
        if n = -1 then None
        else Some n

    member __.GroupNumbers() =
        __.Regex.GetGroupNumbers()

    member __.IsMatch input =
        __.Regex.IsMatch input

    member __.IsMatch (input, startAt) =
        __.Regex.IsMatch(input, startAt)

    member __.Match input =
        FsMatch (__.Regex, __.Regex.Match input)

    member __.Match (input, startAt) =
        FsMatch (__.Regex, __.Regex.Match(input, startAt))

    member __.Match (input, startAt, length) =
        FsMatch (__.Regex, __.Regex.Match(input, startAt, length))

    member __.Matches input =
        (__.Regex, __.Regex.Matches input)
        ||> Common.arrayFromMatches

    member __.Matches (input, startAt) =
        (__.Regex, __.Regex.Matches(input, startAt))
        ||> Common.arrayFromMatches

    member __.MatchTimeout =
        __.Regex.MatchTimeout

    member __.Prefixes
        with get() = _prefixes
        and set(value) = _prefixes <- value

    member __.RegexOptions = _regexOptions

    member __.Replace (input, (replacement : string)) =
        __.Regex.Replace(input, replacement)

    member __.Replace (input, (evalutor : MatchEvaluator)) =
        __.Regex.Replace(input, evalutor)

    member __.Replace (input, (replacement : string), count) =
        __.Regex.Replace(input, replacement, count)

    member __.Replace (input, (evalutor : MatchEvaluator), count) =
        __.Regex.Replace(input, evalutor, count)

    member __.Replace (input, (replacement : string), count, startAt) =
        __.Regex.Replace(input, replacement, count, startAt)

    member __.Replace (input, (evalutor : MatchEvaluator), count, startAt) =
        __.Regex.Replace(input, evalutor, count, startAt)

    member __.RightToLeft =
        __.Regex.RightToLeft

    member __.Source
        with get() = _source
        and set(value) = _source <- value

    member __.Suffixes
        with get() = _suffixes
        and set(value) = _suffixes <- value

    member  __.Split input =
        __.Regex.Split input

    member  __.Split (input, count) =
        __.Regex.Split(input, count)

    member  __.Split (input, count, startAt) =
        __.Regex.Split(input, count, startAt)

let firstMatch regularExpression input =
    let regex = new Regex(regularExpression)
    FsMatch (regex, Regex.Match(input, regularExpression))

let firstMatchOpt regularExpression regexOptions input =
    let regex = new Regex(regularExpression)
    FsMatch (regex, Regex.Match(input, regularExpression, regexOptions))

let matchAt regularExpression startAt input =
    let regex = new Regex(regularExpression)
    FsMatch (regex, regex.Match (input, startAt))

let matchAtOpt regularExpression regexOptions startAt input =
    let regex = new Regex(regularExpression, regexOptions)
    FsMatch (regex, regex.Match (input, startAt))

let matchAtFor regularExpression startAt length input =
    let regex = new Regex(regularExpression)
    FsMatch (regex, regex.Match (input, startAt, length))

let matchAtForOpt regularExpression regexOptions startAt length input =
    let regex = new Regex(regularExpression, regexOptions)
    FsMatch (regex, regex.Match (input, startAt, length))

let matches regularExpression input =
    let regex = new Regex(regularExpression)
    (regex, regex.Matches(input))
    ||> Common.arrayFromMatches

let matchesOpt regularExpression regexOptions input =
    let regex = new Regex(regularExpression, regexOptions)
    (regex, regex.Matches(input))
    ||> Common.arrayFromMatches

let matchesAt regularExpression startAt input =
    let regex = new Regex(regularExpression)
    (regex, regex.Matches(input, startAt))
    ||>Common.arrayFromMatches

let matchesAtOpt regularExpression regexOptions startAt input =
    let regex = new Regex(regularExpression, regexOptions)
    (regex, regex.Matches(input, startAt))
    ||> Common.arrayFromMatches

let replace regularExpression (replacement : string) input =
    Regex.Replace(input, regularExpression, replacement)

let replaceOpt regularExpression regexOptions (replacement : string) input =
    Regex.Replace(input, regularExpression, replacement, regexOptions)

let replaceByMatch regularExpression (evalutor : MatchEvaluator) input =
    Regex.Replace(input, regularExpression, evalutor)

let replaceByMatchOpt regularExpression regexOptions (evalutor : MatchEvaluator) input =
    Regex.Replace(input, regularExpression, evalutor, regexOptions)

let replaceMaxTimes regularExpression (replacement : string) count input =
    (new Regex(regularExpression)).Replace(input, replacement, count )

let replaceMaxTimesOpt regularExpression regexOptions (replacement : string) count input =
    (new Regex(regularExpression, regexOptions)).Replace(input, replacement, count )

let replaceByMatchMaxTimes regularExpression (evalutor : MatchEvaluator) count input =
    (new Regex(regularExpression)).Replace(input, evalutor, count)

let replaceByMatchMaxTimesOpt regularExpression regexOptions (evalutor : MatchEvaluator) count input =
    (new Regex(regularExpression, regexOptions)).Replace(input, evalutor, count)

let replaceMaxTimesStartAt regularExpression (replacement : string) count startAt input =
    (new Regex(regularExpression)).Replace(input, replacement, count, startAt)

let replaceMaxTimesStartAtOpt regularExpression regexOptions (replacement : string) count startAt input =
    (new Regex(regularExpression, regexOptions)).Replace(input, replacement, count, startAt)

let replaceByMatchMaxTimesStartAt regularExpression (evalutor : MatchEvaluator) count startAt input =
    (new Regex(regularExpression)).Replace(input, evalutor, count, startAt)

let replaceByMatchMaxTimesStartAtOpt regularExpression regexOptions (evalutor : MatchEvaluator) count startAt input =
    (new Regex(regularExpression, regexOptions)).Replace(input, evalutor, count, startAt)

let split regularExpression input =
    Regex.Split(input, regularExpression)

let splitOpt regularExpression regexOptions input =
    Regex.Split(input, regularExpression, regexOptions)

let splitMaxTimes regularExpression count input =
    (new Regex(regularExpression)).Split (input, count)

let splitMaxTimesOpt regularExpression regexOptions count input =
    (new Regex(regularExpression, regexOptions)).Split (input, count)

let splitMaxTimesStartAt regularExpression count startAt input =
    (new Regex(regularExpression)).Split (input, count, startAt)

let splitMaxTimesStartAtOpt regularExpression regexOptions count startAt input =
    (new Regex(regularExpression, regexOptions)).Split (input, count, startAt)

let capture regularExpression (groupName : string) input =
    let match' = (new Regex(regularExpression)).Match input
    match'.Groups.[groupName].Value

let captureOpt regularExpression regexOptions (groupName : string) input =
    let match' = (new Regex(regularExpression, regexOptions)).Match input
    match'.Groups.[groupName].Value

let captureGroup regularExpression (groupName : string) input =
    let regex = new Regex(regularExpression)

    let match' = regex.Match input
    (groupName, match'.Groups.[groupName])
    |> FsGroup

let captureGroupOpt regularExpression regexOptions (groupName : string) input =
    let regex = new Regex(regularExpression, regexOptions)

    let match' = regex.Match input
    (groupName, match'.Groups.[groupName])
    |> FsGroup

let groupNames regularExpression =
    (new Regex(regularExpression)).GetGroupNames()

let groupNumbers regularExpression =
    (new Regex(regularExpression)).GetGroupNumbers()

let isMatch regularExpression input =
    Regex.IsMatch(input, regularExpression)

let isMatchOpt regularExpression regexOptions input =
    Regex.IsMatch(input, regularExpression, regexOptions)

let isMatchAt regularExpression startAt input =
    (new Regex(regularExpression)).IsMatch (input, startAt)

let isMatchAtOpt regularExpression regexOptions startAt input =
    (new Regex(regularExpression, regexOptions)).IsMatch (input, startAt)


text:
module CommonFsRegEx

open FsRegEx

/// From http://emailregex.com/
let Email = new FsRegEx(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}")

let Url = new FsRegEx(@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[^-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[^-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w_]*)?\??(?:[-\+=&;%@.\w-_]*)#?(?:[\w]*))?)")


text:
/// Functions supporting composable verbal expression natural language regular expressions.
module VerbalExpressions

open System
open System.Text.RegularExpressions
open FsRegEx

///Searches the specified input string for the first occurrence of the FsRegEx.
val firstMatch : input : string -> fsRegEx : FsRegEx -> FsMatch

///Searches the specified input string for the first occurrence of the FsRegEx beginning at the specified starting position.
val matchAt : input : string -> startAt : int -> fsRegEx : FsRegEx -> FsMatch

///Searches the specified input string for the first occurrence of the FsRegEx beginning at the starting position for the length.
val matchAtFor : input : string -> startAt : int ->  length : int -> fsRegEx : FsRegEx -> FsMatch

///Searches the specified input string for all occurrences of a regular expression.
val matches : input : string -> fsRegEx : FsRegEx -> FsMatch[]

///Searches the input string for all occurrence of a regular expression, beginning at the specified starting position.
val matchesAt : input : string -> startAt : int -> fsRegEx : FsRegEx -> FsMatch[]

///In input string replaces all strings that match regular expression pattern with replacement string.
val replace : input : string -> replacement : string -> fsRegEx : FsRegEx -> string

///In input string replaces all strings that match regular expression with string returned by MatchEvaluator delegate.
val replaceByMatch : input : string -> evalutor : MatchEvaluator -> fsRegEx : FsRegEx -> string

///In input string replaces a specified maximum number of strings that match regular expression with replacement string.
val replaceMaxTimes : input : string -> replacement : string -> count : int -> fsRegEx : FsRegEx -> string

///In input string replaces a specified maximum number of strings that match a regular expression with string returned by MatchEvaluator delegate.
val replaceByMatchMaxTimes : input : string -> evalutor : MatchEvaluator -> count : int -> fsRegEx : FsRegEx -> string

///In input string beginning at start at position replaces a specified maximum number of strings that match regular expression with replacement string.
val replaceMaxTimesStartAt : input : string -> replacement : string -> count : int -> startAt : int -> fsRegEx : FsRegEx -> string

///In input string beginning at start at position replaces a specified maximum number of strings that match a regular expression with string returned by MatchEvaluator delegate.
val replaceByMatchMaxTimesStartAt : input : string -> evalutor : MatchEvaluator -> count : int -> startAt : int -> fsRegEx : FsRegEx -> string

///Splits input string into an array of substrings at the positions defined by regular expression.
val split : input : string -> fsRegEx : FsRegEx -> array<string>

///Splits input string a specified maximum number of times into an array of substrings at the positions defined by regular expression.
val splitMaxTimes : input : string -> count : int -> fsRegEx : FsRegEx -> array<string>

///Splits input string, begining at start position, a specified maximum number of times into an array of substrings at the positions defined by regular expression.
val splitMaxTimesStartAt : input : string -> count : int -> startAt : int -> fsRegEx : FsRegEx -> array<string>

///Return new FsRegEx with new RegExOptions.
val resetRegexOptions : newRegexOptions : RegexOptions option -> fsRegEx : FsRegEx -> FsRegEx

///Match and select groupname value.
val capture : input : string -> groupName : string -> fsRegEx : FsRegEx -> string

///Indicates whether the regular expression finds a match in the input string.
val isMatch : value : string -> fsRegEx : FsRegEx -> bool

///Indicates whether the regular expression finds a match in the input string beginning at the specified starting position.
val isMatchAt : value : string -> startAt : int -> fsRegEx : FsRegEx -> bool

///Returns an array of capturing group names for the regular expression.
val groupNames : fsRegEx : FsRegEx -> array<string>

///Returns an array of capturing group numbers that correspond to group names in an array.
val groupNumbers : fsRegEx : FsRegEx -> array<int>

///Value of regular expression.
val toString : fsRegEx : FsRegEx -> string

///Mark the expression to start at the beginning of the line; ^
val startOfLine : fsRegEx : FsRegEx -> FsRegEx

///Mark the expression to end at the last character of the line; $
val endOfLine : fsRegEx : FsRegEx -> FsRegEx

///Append unescaped literal expression to the expression.
val add : value : string -> fsRegEx : FsRegEx -> FsRegEx

///Append escaped literal expression to the expression. (Same as find.)
val then' : value : string -> fsRegEx : FsRegEx -> FsRegEx

///Append escaped literal expression to the expression. (Same as then'.)
val find : value : string -> fsRegEx : FsRegEx -> FsRegEx

///Add escaped string to the expression that might appear once (or not); (value)?
val maybe : value : string -> fsRegEx : FsRegEx -> FsRegEx

///Zero or more of any character; (.*)
val anything : fsRegEx : FsRegEx -> FsRegEx

///Zero or more of any character except escaped character(s); ([^value]*)
val anythingBut : value : string -> fsRegEx : FsRegEx -> FsRegEx

///One or more of any character; (.+)
val something : fsRegEx : FsRegEx -> FsRegEx

///One or more of any character except escaped character; ([^%s]+)
val somethingBut : value : string -> fsRegEx : FsRegEx -> FsRegEx

///Refers to nth occurence of capturing groups; \ordinal
val backReference : ordinal : int -> fsRegEx : FsRegEx -> FsRegEx

///Refers to named capturing group; \k<groupname>
val namedBackReference : groupname : string -> fsRegEx : FsRegEx -> FsRegEx

///Add expression to match a range (or multiple ranges), unescaped values.
val range : collection : seq<obj> -> fsRegEx : FsRegEx -> FsRegEx

///Matches universal line break expression; \n
val lineBreak : fsRegEx : FsRegEx -> FsRegEx

///Same as lineBreak; \n
val br : fsRegEx : FsRegEx ->  FsRegEx

///Matches a tab character; \t
val tab : fsRegEx : FsRegEx -> FsRegEx

///Matches any white-space character; \s
val whiteSpace : fsRegEx : FsRegEx -> FsRegEx

///Matches any non-white-space character; \S.
val nonWhiteSpace : fsRegEx : FsRegEx -> FsRegEx

///Expression to match a word; \w+
val word : fsRegEx : FsRegEx -> FsRegEx

///Matches any word character; \w
val wordCharacter  : fsRegEx : FsRegEx -> FsRegEx

///Matches any nonword character; \W
val nonWordCharacter  : fsRegEx : FsRegEx -> FsRegEx

///Matches any decimal digit; \d
val digit  : fsRegEx : FsRegEx -> FsRegEx

///Matches any nondigit; \D
val nonDigit  : fsRegEx : FsRegEx -> FsRegEx

///Matches any single character included in the specified set of escaped characters; [value]
val anyOf : value : string -> fsRegEx : FsRegEx -> FsRegEx

///Same as anyOf.
val any : value : string -> fsRegEx : FsRegEx ->  FsRegEx

///The escaped expression 1 or more times; (value)+
val multiple : value : string -> fsRegEx : FsRegEx -> FsRegEx

///The FsRegEx 1 or more times; (sourceFsRegEx)+
val multipleFsRegEx : sourceFsRegEx : FsRegEx -> fsRegEx : FsRegEx -> FsRegEx

///Or's the regular expression to the regular expression in a FsRegEx.
val or' : regularExpression : string -> fsRegEx : FsRegEx -> FsRegEx

///Return new FsRegEx of two FsRegExs or'ed.
val fsRegExOrFsRegEx : regexOptions : RegexOptions -> fsRegEx : FsRegEx -> fsRegEx : FsRegEx -> FsRegEx

///Begin capture group; (
val beginCapture : fsRegEx : FsRegEx -> FsRegEx

///Begin named capture group ;(?<groupName>
val beginCaptureNamed : groupName : string -> fsRegEx : FsRegEx -> FsRegEx

///End capture group; )
val endCapture : fsRegEx : FsRegEx -> FsRegEx

///Repeat previous exact number of times; {n}
val repeatPrevious : n : int -> FsRegEx -> FsRegEx

///Repeat previous number of times between n and m; {n,m}
val repeatBetweenPrevious : n : int ->  m : int -> FsRegEx -> FsRegEx

///Matches a Unicode character by using hexadecimal representation  (exactly four digits, as represented by nnnn); \unnnn
val unicode : nnnn : string -> FsRegEx -> FsRegEx

///Matches any single character in the Unicode general category; \p{name}
val unicodeCategory : category : Unicode.UnicodeGeneralCategory -> FsRegEx -> FsRegEx

///Matches any single character that is not in the Unicode general category; \P{name}
val notUnicodeCategory : category : Unicode.UnicodeGeneralCategory -> FsRegEx -> FsRegEx

///Matches any single character in the supported named block; \p{name}
val namedBlock : name : Unicode.SupportedNamedBlock -> FsRegEx -> FsRegEx

///Matches any single character that is not in the supported named block; \P{name}
val notNamedBlock : name : Unicode.SupportedNamedBlock -> FsRegEx -> FsRegEx

///Executes a function on a FsRegEx.
val iter : f : (FsRegEx -> unit) -> fsRegEx : FsRegEx -> unit

///Transforms a FsRegEx  with a mapping function
val map : f : (FsRegEx -> FsRegEx) -> fsRegEx : FsRegEx -> FsRegEx

///Applies a function to a FsRegEx and a state returning a state
val fold : f : ('State -> FsRegEx -> 'State) -> state : 'State -> fsRegEx : FsRegEx -> 'State

///Applies a function to a FsRegEx and a state returning a state
val foldBack : f : (FsRegEx -> 'State -> 'State) -> fsRegEx : FsRegEx -> state : 'State -> 'State

///Evaluates the boolean function on the FsRegEx
val exists : f : (FsRegEx -> bool) -> fsRegEx : FsRegEx -> bool


text:
// https://msdn.microsoft.com/en-us/library/e7sf90t3(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System
open System.Text.RegularExpressions

let pattern = @"\b\w+es\b"
let rgx = new Regex(pattern)
let sentence = "Who writes these notes?"

for m in rgx.Matches(sentence) do
    printfn "Found '%s' at position %i" m.Value m.Index

// The example displays the following output:
//       Found 'writes' at position 4
//       Found 'notes' at position 17

sentence
|> FsRegEx.matches pattern
|> Array.iter (fun m -> printfn "Found '%s' at position %i" m.Value m.Index)

// https://msdn.microsoft.com/en-us/library/z9ekkwhs(v=vs.110).aspx

let pattern = @"\b\w+es\b"
let rgx = new Regex(pattern)
let sentence = "Who writes these notes and uses our paper?"

// Get the first match.
let m = rgx.Match(sentence)
if m.Success then
    printfn "Found first 'es' in '%s' at position %i" m.Value m.Index
    // Get any additional matches.
    for m in (rgx.Matches(sentence, m.Index + m.Length)) do
        printfn "Also found '%s' at position %i" m.Value m.Index

// The example displays the following output:
//       Found first 'es' in 'writes' at position 4
//       Also found 'notes' at position 17
//       Also found 'uses' at position 27

let m = FsRegEx.firstMatch pattern sentence

if m.Success then
    printfn "Found first 'es' in '%s' at position %i" m.Value m.Index
    sentence
    |> FsRegEx.matchesAt pattern (m.Index + m.Length)
    |> Array.iter (fun m -> printfn "Also found '%s' at position %i" m.Value m.Index)

// https://msdn.microsoft.com/en-us/library/b9712a7w(v=vs.110).aspx

let pattern = @"\b\w+es\b"
let sentence = "Who writes these notes?"

for m in (Regex.Matches(sentence, pattern)) do
    printfn "Found '%s' at position %i" m.Value m.Index

// The example displays the following output:
//       Found 'writes' at position 4
//       Found 'notes' at position 17

// https://msdn.microsoft.com/en-us/library/b49yw9s8(v=vs.110).aspx

let pattern = @"\b\w+es\b"
let sentence = "NOTES: Any notes or comments are optional."

// Call Matches method without specifying any options.
for m in (Regex.Matches(sentence, pattern)) do
    printfn "Found '%s' at position %i" m.Value m.Index
printfn ""

// Call Matches method for case-insensitive matching.
for m in (Regex.Matches(sentence, pattern, RegexOptions.IgnoreCase)) do
    printfn "Found '%s' at position %i" m.Value m.Index

// The example displays the following output:
//       Found 'notes' at position 11
//
//       Found 'NOTES' at position 0
//       Found 'notes' at position 11

// https://msdn.microsoft.com/en-us/library/hh160201(v=vs.110).aspx

let pattern = @"\b\w+es\b"
let sentence = "NOTES: Any notes or comments are optional."

// Call Matches method without specifying any options.
try
    for m in (Regex.Matches(sentence, pattern,
                                        RegexOptions.None,
                                        TimeSpan.FromSeconds(1.0))) do
        printfn "Found '%s' at position %i" m.Value m.Index
with
    | :? RegexMatchTimeoutException as e ->
        ()
    // Do Nothing: Assume that timeout represents no match.
printfn ""

// Call Matches method for case-insensitive matching.
try
    for match' in (Regex.Matches(sentence, pattern, RegexOptions.IgnoreCase)) do
        printfn "Found '%s' at position %i" match'.Value match'.Index
with
    | :? RegexMatchTimeoutException as e ->
        ()
    // Do Nothing: Assume that timeout represents no match.

// The example displays the following output:
//       Found 'notes' at position 11
//
//       Found 'NOTES' at position 0
//       Found 'notes' at position 11


text:
// Warning: generated file; your changes could be lost when a new file is generated.
#I __SOURCE_DIRECTORY__
#load "load-references-release.fsx"
#load "../UniCode.fs"
      "../Common.fs"
      "../FsRegEx.fsi"
      "../FsRegEx.fs"
      "../VerbalExpression.fsi"
      "../VerbalExpression.fs"
      "../CommonFsRegEx.fsi"
      "../CommonFsRegEx.fs"


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.getgroupnames(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

let ShowMatches (r : Regex)  (m : Match) =
    let names = r.GetGroupNames()

    printfn "Named Groups:"

    for name in names do
         let grp = m.Groups.[name]
         printfn "   %s: '%s'" name grp.Value
    ()

let pattern = @"\b(?<FirstWord>\w+)\s?((\w+)\s)*(?<LastWord>\w+)?(?<Punctuation>\p{Po})"
let input = "The cow jumped over the moon."
let rgx = new Regex(pattern)
let m = rgx.Match(input)
if m.Success then
    ShowMatches rgx m
else ()

//       Named Groups:
//          0: 'The cow jumped over the moon.'
//          1: 'the '
//          2: 'the'
//          FirstWord: 'The'
//          LastWord: 'moon'
//          Punctuation: '.'

let pattern' = @"\b(?<FirstWord>\w+)\s?((\w+)\s)*(?<LastWord>\w+)?(?<Punctuation>\p{Po})"
let input' = "The cow jumped over the moon."

let m' = FsRegEx.firstMatch pattern' input'

printfn "Named Groups:"

m'.Groups()
|> Array.iter (fun g -> printfn "   %s: '%s'" g.Name g.Value)


text:
// https://msdn.microsoft.com/en-us/library/ze12yx1d(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions
open FsRegEx

let regex = new Regex("-")         // Split on hyphens.
let substrings = regex.Split("plum--pear")

for m in substrings do
    printfn "'%s'" m

// The example displays the following output:
//    'plum'
//    ''
//    'pear'

let pattern = @"\d+"
let rgx = new Regex(pattern)
let input = "123ABCDE456FGHIJKL789MNOPQ012"

string[] result = rgx.Split(input)
for (int ctr = 0 ctr < result.Length ctr++) {
    Console.Write("'{0}'", result[ctr])
    if (ctr < result.Length - 1)
    Console.Write(", ")
}
printfn )

// The example displays the following output:
//       '', 'ABCDE', 'FGHIJKL', 'MNOPQ', ''

Regex regex = new Regex("(-)")         // Split on hyphens.
string[] substrings = regex.Split("plum-pear")
foreach (string match in substrings)
{
    printfn "'{0}'", match)
}
// The example displays the following output:
//    'plum'
//    '-'
//    'pear'

string input = @"07/14/2007"
string pattern = @"(-)|(/)"
Regex regex = new Regex(pattern)
foreach (string result in regex.Split(input))
{
    printfn "'{0}'", result)
}
// Under .NET 1.0 and 1.1, the method returns an array of
// 3 elements, as follows:
//    '07'
//    '14'
//    '2007'
//
// Under .NET 2.0 and later, the method returns an array of
// 5 elements, as follows:
//    '07'
//    '/'
//    '14'
//    '/'
//    '2007'

string input = "characters"
Regex regex = new Regex("")
string[] substrings = regex.Split(input)
Console.Write("{")
for(int ctr = 0 ctr < substrings.Length ctr++)
{
    Console.Write(substrings[ctr])
    if (ctr < substrings.Length - 1)
    Console.Write(", ")
}
printfn "}")

// The example displays the following output:
//    {, c, h, a, r, a, c, t, e, r, s, }

// https://msdn.microsoft.com/en-us/library/98awefz7(v=vs.110).aspx

string pattern = @"\d+"
Regex rgx = new Regex(pattern)
string input = "123ABCDE456FGHIJKL789MNOPQ012"

string[] result = rgx.Split(input, 3)
for (int ctr = 0 ctr < result.Length ctr++) {
    Console.Write("'{0}'", result[ctr])
    if (ctr < result.Length - 1)
    Console.Write(", ")
}
printfn )

// The example displays the following output:
//       '', 'ABCDE', 'FGHIJKL789MNOPQ012'

string pattern = "(-)"
string input = "apple-apricot-plum-pear-banana"
Regex regex = new Regex(pattern)         // Split on hyphens.
string[] substrings = regex.Split(input, 4)
foreach (string match in substrings)
{
    printfn "'{0}'", match)
}
// The example displays the following output:
//       'apple'
//       '-'
//       'apricot'
//       '-'
//       'plum'
//       '-'
//       'pear-banana'

string input = @"07/14/2007"
string pattern = @"(-)|(/)"
Regex regex = new Regex(pattern)
foreach (string result in regex.Split(input, 2))
{
    printfn "'{0}'", result)
}
// Under .NET 1.0 and 1.1, the method returns an array of
// 2 elements, as follows:
//    '07'
//    '14/2007'
//
// Under .NET 2.0 and later, the method returns an array of
// 3 elements, as follows:
//    '07'
//    '/'
//    '14/2007'

// https://msdn.microsoft.com/en-us/library/8yttk7sy(v=vs.110).aspx

string input = "plum--pear"
string pattern = "-"            // Split on hyphens

string[] substrings = Regex.Split(input, pattern)
foreach (string match in substrings)
{
    printfn "'{0}'", match)
}
// The method displays the following output:
//    'plum'
//    ''
//    'pear'

string pattern = @"\d+"
string input = "123ABCDE456FGHIJKL789MNOPQ012"
string[] result = Regex.Split(input, pattern)
for (int ctr = 0 ctr < result.Length ctr++) {
    Console.Write("'{0}'", result[ctr])
    if (ctr < result.Length - 1)
    Console.Write(", ")
}
printfn )

// The example displays the following output:
//       '', 'ABCDE', 'FGHIJKL', 'MNOPQ', ''

string input = "plum-pear"
string pattern = "(-)"

string[] substrings = Regex.Split(input, pattern)    // Split on hyphens
foreach (string match in substrings)
{
    printfn "'{0}'", match)
}
// The example displays the following output:
//    'plum'
//    '-'
//    'pear'

string input = @"07/14/2007"
string pattern = @"(-)|(/)"

foreach (string result in Regex.Split(input, pattern))
{
    printfn "'{0}'", result)
}
// In .NET 1.0 and 1.1, the method returns an array of
// 3 elements, as follows:
//    '07'
//    '14'
//    '2007'
//
// In .NET 2.0 and later, the method returns an array of
// 5 elements, as follows:
//    '07'
//    '/'
//    '14'
//    '/'
//    '2007'

string input = "characters"
string[] substrings = Regex.Split(input, "")
Console.Write("{")
for(int ctr = 0 ctr < substrings.Length ctr++)
{
    Console.Write("'{0}'", substrings[ctr])
    if (ctr < substrings.Length - 1)
    Console.Write(", ")
}
printfn "}")

// The example produces the following output:
//    {'', 'c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', 's', ''}

// https://msdn.microsoft.com/en-us/library/byy2946e(v=vs.110).aspx

string pattern = "[a-z]+"
string input = "Abc1234Def5678Ghi9012Jklm"
string[] result = Regex.Split(input, pattern,
                            RegexOptions.IgnoreCase)
for (int ctr = 0 ctr < result.Length ctr++) {
    Console.Write("'{0}'", result[ctr])
    if (ctr < result.Length - 1)
    Console.Write(", ")
}
printfn )

// The example displays the following output:
//       '', '1234', '5678', '9012', ''

string input = "plum-pear"
string pattern = "(-)"

string[] substrings = Regex.Split(input, pattern)    // Split on hyphens
foreach (string match in substrings)
{
    printfn "'{0}'", match)
}
// The example displays the following output:
//    'plum'
//    '-'
//    'pear'

string input = @"07/14/2007"
string pattern = @"(-)|(/)"

foreach (string result in Regex.Split(input, pattern))
{
    printfn "'{0}'", result)
}
// In .NET 1.0 and 1.1, the method returns an array of
// 3 elements, as follows:
//    '07'
//    '14'
//    '2007'
//
// In .NET 2.0 and later, the method returns an array of
// 5 elements, as follows:
//    '07'
//    '/'
//    '14'
//    '/'
//    '2007'

// https://msdn.microsoft.com/en-us/library/hh160264(v=vs.110).aspx

string pattern = "[a-z]+"
string input = "Abc1234Def5678Ghi9012Jklm"
string[] result = Regex.Split(input, pattern,
                            RegexOptions.IgnoreCase,
                            TimeSpan.FromMilliseconds(500))
for (int ctr = 0 ctr < result.Length ctr++) {
    Console.Write("'{0}'", result[ctr])
    if (ctr < result.Length - 1)
    Console.Write(", ")
}
printfn )

// The example displays the following output:
//       '', '1234', '5678', '9012', ''

string input = "plum-pear"
string pattern = "(-)"

string[] substrings = Regex.Split(input, pattern)    // Split on hyphens
foreach (string match in substrings)
{
    printfn "'{0}'", match)
}

// The example displays the following output:
//    'plum'
//    '-'
//    'pear'

string input = @"07/14/2007"
string pattern = @"(-)|(/)"

foreach (string result in Regex.Split(input, pattern))
{
    printfn "'{0}'", result)
}

// In .NET 1.0 and 1.1, the method returns an array of
// 3 elements, as follows:
//    '07'
//    '14'
//    '2007'
//
// In .NET 2.0 and later, the method returns an array of
// 5 elements, as follows:
//    '07'
//    '/'
//    '14'
//    '/'
//    '2007'


text:
#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions
open FsRegEx

let emailregex = new Regex("(?<user>[^@]+)@(?<host>.+)")

let printMatch (m : Match) s =

    if m.Success  then
        m.Groups.["user"].Value
        |> printfn "User: %s"
        m.Groups.["host"].Value
        |> printfn "Host: %s"
        m.Captures
        |> printfn "%A"
    else
        printfn "%s is not a valid email address" s

let s = "johndoe@tempuri.org"
let m = emailregex.Match(s)

let s' = "jackfoxy@gmail.com"
let m' = emailregex.Match(s')

printMatch m s

printMatch m' s'

let emailFsRegEx = new FsRegEx("(?<user>[^@]+)@(?<host>.+)")

emailFsRegEx

//@@@@@@@@@@@@@@@@@@@@@@@
let parseRegexTimeStamp (regex : Regex) source =
    try
        let m = regex.Matches source
        m.[0].Groups.[1].Value
        //|> Success
    with _ ->
        sprintf "cannot parse timestamp from source: %s" source
       // |> Failure

//@@@@@@@@@@@@@@@@@@@@@@@

let parseTimeStamp (fsRegEx : FsRegEx) source =
    try
        let m = fsRegEx.Matches source
        m.[0].Groups().[1].Value
        //|> Success
    with _ ->
        sprintf "cannot parse timestamp from source: %s" source
       // |> Failure

let timeStampFsRegEx = (new FsRegEx("\"timeStamp\"\s*:\s*\"(\d{4}-\d{2}-\d{2}-\d{2}-\d{2})\""))
let timeStampRegex = (new Regex("\"timeStamp\"\s*:\s*\"(\d{4}-\d{2}-\d{2}-\d{2}-\d{2})\""))

let source1 = """ "quick": false,
        "timeStamp": "2016-07-14-08-14"
    } """

let source2 = """ "quick": false,
        "timeStamp": "2015-06-10-11-12"
    } """

parseRegexTimeStamp timeStampRegex source1
parseRegexTimeStamp timeStampRegex source2

//bug:
parseTimeStamp timeStampFsRegEx source1
parseTimeStamp timeStampFsRegEx source2

//@@@@@@@@@@@@@@@@@@@@

let text = "One car red car blue car";
let pat = @"(\w+)\s+(car)";

let fsMatches = matches pat text

let groupNumberRegExp = @"COD(?<GroupNumber>[0-9]{3})END"
let groupNumberName = "GroupNumber"

capture groupNumberRegExp groupNumberName "COD123END"
|> printfn "%s"

let carRegExp = @"(\w+)\s+(car)"

sprintf "%s %s %s" "One car" "red car" "blue car"
|> matches carRegExp
|> Array.map (fun m -> m.Value)
|> Array.iter(fun x -> printfn "%s" x)

sprintf "%s" "COD123END"
|> capture groupNumberRegExp groupNumberName
|> printfn "%s"


text:
// https://msdn.microsoft.com/en-us/library/3y21t6y4(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open FsRegEx
open System.Text.RegularExpressions

let partNumbers = [| "1298-673-4192"; "A08Z-931-468A";
                        "_A90-123-129X"; "12345-KKA-1230";
                        "0919-2893-1256" |]
let rgx = new Regex(@"^[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]$")

for partNumber in partNumbers do
    printfn "%s %s a valid part number."
                    partNumber
                    (if (rgx.IsMatch(partNumber)) then "is"
                     else "is not")

// The example displays the following output:
//       1298-673-4192 is a valid part number.
//       A08Z-931-468A is a valid part number.
//       _A90-123-129X is not a valid part number.
//       12345-KKA-1230 is not a valid part number.
//       0919-2893-1256 is not a valid part number.

let fsRegEx = new FsRegEx(@"^[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]$")

for partNumber in partNumbers do
    printfn "%s %s a valid part number."
                    partNumber
                    (if (fsRegEx.IsMatch(partNumber)) then "is"
                     else "is not")

// https://msdn.microsoft.com/en-us/library/z1hx7a5y(v=vs.110).aspx

let partNumbers = [| "Part Number: 1298-673-4192"; "Part No: A08Z-931-468A";
                        "_A90-123-129X"; "123K-000-1230";
                        "SKU: 0919-2893-1256" |]
let rgx = new Regex(@"[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]$")

for partNumber in partNumbers do
    let start = partNumber.IndexOf(':')
    if (start >= 0) then
        printfn "%s %s a valid part number."
                        partNumber
                        (if (rgx.IsMatch(partNumber, start)) then "is" else "is not")
    else
        printfn "Cannot find starting position in %s." partNumber

// The example displays the following output:
//       Part Number: 1298-673-4192 is a valid part number.
//       Part No: A08Z-931-468A is a valid part number.
//       Cannot find starting position in _A90-123-129X.
//       Cannot find starting position in 123K-000-1230.
//       SKU: 0919-2893-1256 is not a valid part number.

let fsRegEx = new FsRegEx(@"[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]$")

for partNumber in partNumbers do
    let start = partNumber.IndexOf(':')
    if (start >= 0) then
        printfn "%s %s a valid part number."
                        partNumber
                        (if (fsRegEx.IsMatch(partNumber, start)) then "is" else "is not")
    else
        printfn "Cannot find starting position in %s." partNumber

// https://msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx

let partNumbers = [| "1298-673-4192"; "A08Z-931-468A";
                        "_A90-123-129X"; "12345-KKA-1230";
                        "0919-2893-1256" |]
let pattern = @"^[a-zA-Z0-9]\d{2}[a-zA-Z0-9](-\d{3}){2}[A-Za-z0-9]$"

for partNumber in partNumbers do
    printfn "%s %s a valid part number."
                    partNumber
                    (if (Regex.IsMatch(partNumber, pattern)) then
                        "is"
                     else "is not")

// The example displays the following output:
//       1298-673-4192 is a valid part number.
//       A08Z-931-468A is a valid part number.
//       _A90-123-129X is not a valid part number.
//       12345-KKA-1230 is not a valid part number.
//       0919-2893-1256 is not a valid part number.

// https://msdn.microsoft.com/en-us/library/ktzf2d23(v=vs.110).aspx

let pattern = @"^[A-Z0-9]\d{2}[A-Z0-9](-\d{3}){2}[A-Z0-9]$"

for partNumber in partNumbers do
    printfn "%s %s a valid part number."
                    partNumber
                    (if (Regex.IsMatch(partNumber, pattern, RegexOptions.IgnoreCase)) then
                        "is"
                     else "is not")

// The example displays the following output:
//       1298-673-4192 is a valid part number.
//       A08Z-931-468a is a valid part number.
//       _A90-123-129X is not a valid part number.
//       12345-KKA-1230 is not a valid part number.
//       0919-2893-1256 is not a valid part number

// https://msdn.microsoft.com/en-us/library/hh160210(v=vs.110).aspx

for partNumber in partNumbers do
    try
        printfn "%s %s a valid part number."
                        partNumber
                        (if (Regex.IsMatch(partNumber, pattern, RegexOptions.IgnoreCase, (System.TimeSpan.FromMilliseconds(500.)))) then
                            "is"
                         else "is not")
    with :? RegexMatchTimeoutException as e ->

        printfn "Timeout after %i seconds matching %s."
            e.MatchTimeout.Seconds e.Input

// The example displays the following output:
//       1298-673-4192 is a valid part number.
//       A08Z-931-468a is a valid part number.
//       _A90-123-129X is not a valid part number.
//       12345-KKA-1230 is not a valid part number.
//       0919-2893-1256 is not a valid part number.

for partNumber in partNumbers do
    try
        printfn "%s %s a valid part number."
                        partNumber
                        (if (Regex.IsMatch(partNumber, pattern, RegexOptions.IgnoreCase, (System.TimeSpan.FromMilliseconds(500.)))) then
                            "is"
                         else "is not")
    with :? RegexMatchTimeoutException as e ->

        printfn "Timeout after %i seconds matching %s."
            e.MatchTimeout.Seconds e.Input


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.matchtimeout(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System
open System.Text.RegularExpressions

let domain = AppDomain.CurrentDomain
// Set a timeout interval of 2 seconds.
domain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromSeconds(2.))
let timeout = domain.GetData("REGEX_DEFAULT_MATCH_TIMEOUT")
printfn "Default regex match timeout: %O"
                    (if (isNull timeout) then ("<null>" :> obj) else timeout)

let rgx = new Regex("[aeiouy]")
printfn "Regular expression pattern: %s" (rgx.ToString())
printfn "Timeout interval for this regex: %f seconds" rgx.MatchTimeout.TotalSeconds


text:
// https://msdn.microsoft.com/en-us/library/twcw2f1c(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

let text = "One car red car blue car"
let pat = @"(\w+)\s+(car)"

// Instantiate the regular expression object.
let r = new Regex(pat, RegexOptions.IgnoreCase)

// Match the regular expression pattern against a text string.
let mutable m = r.Match(text)
let mutable matchCount = 0
while m.Success do
    matchCount <- matchCount + 1
    printfn "Match%i" matchCount
    for (int i = 1 i <= 2 i++)
        {
        Group g = m.Groups[i]
        printfn "Group"+i+"='" + g + "'")
        CaptureCollection cc = g.Captures
        for (int j = 0 j < cc.Count j++)
        {
            Capture c = cc[j]
            System.printfn "Capture"+j+"='" + c + "', Position="+c.Index)
        }
        }
    m = m.NextMatch()
// This example displays the following output:
//       Match1
//       Group1='One'
//       Capture0='One', Position=0
//       Group2='car'
//       Capture0='car', Position=4
//       Match2
//       Group1='red'
//       Capture0='red', Position=8
//       Group2='car'
//       Capture0='car', Position=12
//       Match3
//       Group1='blue'
//       Capture0='blue', Position=16
//       Group2='car'
//       Capture0='car', Position=21

// https://msdn.microsoft.com/en-us/library/h09aybcd(v=vs.110).aspx
//(no code sample)

// https://msdn.microsoft.com/en-us/library/0z2heewz(v=vs.110).aspx

let input = "ablaze beagle choral dozen elementary fanatic " +
                "glaze hunger inept jazz kitchen lemon minus " +
                "night optical pizza quiz restoration stamina " +
                "train unrest vertical whiz xray yellow zealous"
let pattern = @"\b\w*z+\w*\b"

let mutable m = Regex.Match(input, pattern)

while m.Success do
    printfn "'%s' found at position %i" m.Value m.Index
    m <- m.NextMatch()

// The example displays the following output:
//    'ablaze' found at position 0
//    'dozen' found at position 21
//    'glaze' found at position 46
//    'jazz' found at position 65
//    'pizza' found at position 104
//    'quiz' found at position 110
//    'whiz' found at position 157
//    'zealous' found at position 174

FsRegEx.matches pattern input
|> Array.iter (fun m -> printfn "'%s' found at position %i" m.Value m.Index)

// https://msdn.microsoft.com/en-us/library/bk1x0726(v=vs.110).aspx

let pattern = @"\ba\w*\b"
let input = "An extraordinary day dawns with each new day."
let m = Regex.Match(input, pattern, RegexOptions.IgnoreCase)

if m.Success then
    printfn "Found '%s' at position %i." m.Value m.Index

// The example displays the following output:
//        Found 'An' at position 0.

let m = FsRegEx.firstMatchOpt pattern RegexOptions.IgnoreCase input

if m.Success then
    printfn "Found '%s' at position %i." m.Value m.Index

// https://msdn.microsoft.com/en-us/library/hh160204(v=vs.110).aspx
// (no code sample)


text:
// Warning: generated file; your changes could be lost when a new file is generated.
#I __SOURCE_DIRECTORY__
#r "System.Core.dll"
#r "System.dll"
#r "System.Numerics.dll"


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.groupcollection(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

let pattern = @"\b(\w+?)([\u00AE\u2122])"
let input = "Microsoft® Office Professional Edition combines several office " +
                "productivity products, including Word, Excel®, Access®, Outlook®, " +
                "PowerPoint®, and several others. Some guidelines for creating " +
                "corporate documents using these productivity tools are available " +
                "from the documents created using Silverlight™ on the corporate " +
                "intranet site."

let matches = Regex.Matches(input, pattern)
for match' in matches do
    let groups = match'.Groups
    printfn "%s: %s" groups.[2].Value groups.[1].Value

printfn ""
printfn "Found %i trademarks or registered trademarks." matches.Count

// ®: Microsoft
// ®: Excel
// ®: Access
// ®: Outlook
// ®: PowerPoint
// ™: Silverlight


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.group(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

let pattern = @"(\b(\w+?)[,:;]?\s?)+[?.!]"
let input = "This is one sentence. This is a second sentence."

let match' = Regex.Match(input, pattern)
printfn "Match: %s" match'.Value
let mutable groupCtr = 0

for group in match'.Groups do
    groupCtr <- groupCtr + 1
    printfn "   Group %i: '%s'" groupCtr group.Value
    let mutable captureCtr = 0
    for capture in group.Captures do
        captureCtr <- captureCtr + 1
        printfn "      Capture %i: '%s'" captureCtr capture.Value

// The example displays the following output:
//       Match: This is one sentence.
//          Group 1: 'This is one sentence.'
//             Capture 1: 'This is one sentence.'
//          Group 2: 'sentence'
//             Capture 1: 'This '
//             Capture 2: 'is '
//             Capture 3: 'one '
//             Capture 4: 'sentence'
//          Group 3: 'sentence'
//             Capture 1: 'This'
//             Capture 2: 'is'
//             Capture 3: 'one'
//             Capture 4: 'sentence'

let m' = FsRegEx.firstMatch pattern input
printfn "Match: %s" m'.Value

printfn "Named Groups:"
m'.Groups()
|> Array.iteri (fun i g ->
    printfn "   Group %i: '%s'" i g.Value
    g.Captures()
    |> Array.iteri (fun i c ->
        printfn "      Capture %i: '%s'" i c.Value
        )
    )


text:
// https://msdn.microsoft.com/en-us/library/cft8645c(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions
open System

let capText (m : Match) =
    // Get the matched string.
    let x = m.Value
    // If the first char is lower case...
    if (Char.IsLower(x.[0])) then
        // Capitalize it.
        (Char.ToUpper(x.[0]).ToString()) + (x.Substring(1, x.Length - 1))
    else
        x

let text = "four score and seven years ago"

printfn "text=[%s]" text

let rx = new Regex(@"\w+")

let result = rx.Replace(text, new MatchEvaluator(capText))

printfn "result=[%s]" result

// The example displays the following output:
//       text=[four score and seven years ago]
//       result=[Four Score And Seven Years Ago]

printfn "result=[%s]"
    (text
     |> FsRegEx.replaceByMatch @"\w+" (new MatchEvaluator(capText)) )

// https://msdn.microsoft.com/en-us/library/e47f3dkc(v=vs.110).aspx

public static void Main()
{
    string input = "deceive relieve achieve belief fierce receive"
    string pattern = @"\w*(ie|ei)\w*"
    Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase)
    printfn "Original string: " + input)

    string result = rgx.Replace(input, new MatchEvaluator(Example.ReverseLetter),
                                input.Split(' ').Length / 2)
    printfn "Returned string: " + result)
}

static string ReverseLetter(Match match)
{
    return Regex.Replace(match.Value, "([ie])([ie])", "$2$1",
                        RegexOptions.IgnoreCase)
}
// The example displays the following output:
//    Original string: deceive relieve achieve belief fierce receive
//    Returned string: decieve releive acheive belief fierce receive

// https://msdn.microsoft.com/en-us/library/ms149474(v=vs.110).aspx
// (no code sample)

// https://msdn.microsoft.com/en-us/library/xwewhkd1(v=vs.110).aspx

string input = "This is   text with   far  too   much   " +
                "whitespace."
string pattern = "\\s+"
string replacement = " "
Regex rgx = new Regex(pattern)
string result = rgx.Replace(input, replacement)

printfn "Original String: {0}", input)
printfn "Replacement String: {0}", result)

// The example displays the following output:
//       Original String: This is   text with   far  too   much   whitespace.
//       Replacement String: This is text with far too much whitespace.

// https://msdn.microsoft.com/en-us/library/haekbhys(v=vs.110).aspx

string str = "aabccdeefgghiijkklmm"
string pattern = "(\\w)\\1"
string replacement = "$1"
Regex rgx = new Regex(pattern)

string result = rgx.Replace(str, replacement, 5)
printfn "Original String:    '{0}'", str)
printfn "Replacement String: '{0}'", result)

// The example displays the following output:
//       Original String:    'aabccdeefgghiijkklmm'
//       Replacement String: 'abcdefghijkklmm'

// https://msdn.microsoft.com/en-us/library/3fky5t5f(v=vs.110).aspx

string input = "Instantiating a New Type\n" +
                "Generally, there are two ways that an\n" +
                "instance of a class or structure can\n" +
                "be instantiated. "
string pattern = "^.*$"
string replacement = "\n$&"
Regex rgx = new Regex(pattern, RegexOptions.Multiline)
string result = String.Empty

Match match = rgx.Match(input)
// Double space all but the first line.
if (match.Success)
    result = rgx.Replace(input, replacement, -1, match.Index + match.Length + 1)

printfn result)

// The example displays the following output:
//       Instantiating a New Type
//
//       Generally, there are two ways that an
//
//       instance of a class or structure can
//
//       be instntiated.

// https://msdn.microsoft.com/en-us/library/ht1sxswy(v=vs.110).aspx

public static void Main()
{
    string words = "letter alphabetical missing lack release " +
                    "penchant slack acryllic laundry cease"
    string pattern = @"\w+"
    MatchEvaluator evaluator = new MatchEvaluator(WordScrambler)
    printfn "Original words:")
    printfn words)
    printfn )
    printfn "Scrambled words:")
    printfn Regex.Replace(words, pattern, evaluator))
}

public static string WordScrambler(Match match)
{
    int arraySize = match.Value.Length
    // Define two arrays equal to the number of letters in the match.
    double[] keys = new double[arraySize]
    char[] letters = new char[arraySize]

    // Instantiate random number generator'
    Random rnd = new Random()

    for (int ctr = 0 ctr < match.Value.Length ctr++)
    {
        // Populate the array of keys with random numbers.
        keys[ctr] = rnd.NextDouble()
        // Assign letter to array of letters.
        letters[ctr] = match.Value[ctr]
    }
    Array.Sort(keys, letters, 0, arraySize, Comparer.Default)
    return new String(letters)
}

// The example displays output similar to the following:
//    Original words:
//    letter alphabetical missing lack release penchant slack acryllic laundry cease
//
//    Scrambled words:
//    elrtte iaeabatlpchl igmnssi lcka aerslee hnpatnce ksacl lialcryc dylruna ecase

// https://msdn.microsoft.com/en-us/library/ms149475(v=vs.110).aspx

public static void Main()
{
    string words = "letter alphabetical missing lack release " +
                    "penchant slack acryllic laundry cease"
    string pattern = @"\w+  # Matches all the characters in a word."
    MatchEvaluator evaluator = new MatchEvaluator(WordScrambler)
    printfn "Original words:")
    printfn words)
    printfn )
    printfn "Scrambled words:")
    printfn Regex.Replace(words, pattern, evaluator,
                                    RegexOptions.IgnorePatternWhitespace))
}

public static string WordScrambler(Match match)
{
    int arraySize = match.Value.Length
    // Define two arrays equal to the number of letters in the match.
    double[] keys = new double[arraySize]
    char[] letters = new char[arraySize]

    // Instantiate random number generator'
    Random rnd = new Random()

    for (int ctr = 0 ctr < match.Value.Length ctr++)
    {
        // Populate the array of keys with random numbers.
        keys[ctr] = rnd.NextDouble()
        // Assign letter to array of letters.
        letters[ctr] = match.Value[ctr]
    }
    Array.Sort(keys, letters, 0, arraySize, Comparer.Default)
    return new String(letters)
}
// The example displays output similar to the following:
//    Original words:
//    letter alphabetical missing lack release penchant slack acryllic laundry cease
//
//    Scrambled words:
//    etlert liahepalbcat imsgsni alkc ereelsa epcnnaht lscak cayirllc alnyurd ecsae

// https://msdn.microsoft.com/en-us/library/hh194609(v=vs.110).aspx

public static void Main()
{
    string words = "letter alphabetical missing lack release " +
                    "penchant slack acryllic laundry cease"
    string pattern = @"\w+  # Matches all the characters in a word."
    MatchEvaluator evaluator = new MatchEvaluator(WordScrambler)
    printfn "Original words:")
    printfn words)
    printfn )
    try {
        printfn "Scrambled words:")
        printfn Regex.Replace(words, pattern, evaluator,
                                        RegexOptions.IgnorePatternWhitespace,
                                        TimeSpan.FromSeconds(.25)))
    }
    catch (RegexMatchTimeoutException) {
        printfn "Word Scramble operation timed out.")
        printfn "Returned words:")
    }
}

public static string WordScrambler(Match match)
{
    int arraySize = match.Value.Length
    // Define two arrays equal to the number of letters in the match.
    double[] keys = new double[arraySize]
    char[] letters = new char[arraySize]

    // Instantiate random number generator'
    Random rnd = new Random()

    for (int ctr = 0 ctr < match.Value.Length ctr++)
    {
        // Populate the array of keys with random numbers.
        keys[ctr] = rnd.NextDouble()
        // Assign letter to array of letters.
        letters[ctr] = match.Value[ctr]
    }
    Array.Sort(keys, letters, 0, arraySize, Comparer.Default)
    return new String(letters)
}
// The example displays output similar to the following:
//    Original words:
//    letter alphabetical missing lack release penchant slack acryllic laundry cease
//
//    Scrambled words:
//    etlert liahepalbcat imsgsni alkc ereelsa epcnnaht lscak cayirllc alnyurd ecsae

// https://msdn.microsoft.com/en-us/library/e7f5w83z(v=vs.110).aspx

string input = "This is   text with   far  too   much   " +
                "whitespace."
string pattern = "\\s+"
string replacement = " "
string result = Regex.Replace(input, pattern, replacement)

printfn "Original String: {0}", input)
printfn "Replacement String: {0}", result)

// The example displays the following output:
//       Original String: This is   text with   far  too   much   whitespace.
//       Replacement String: This is text with far too much whitespace.

// Get drives available on local computer and form into a single character expression.
string[] drives = Environment.GetLogicalDrives()
string driveNames = String.Empty
foreach (string drive in drives)
    driveNames += drive.Substring(0,1)
// Create regular expression pattern dynamically based on local machine information.
string pattern = @"\\\\(?i:" + Environment.MachineName + @")(?:\.\w+)*\\((?i:[" + driveNames + @"]))\$"

string replacement = "$1:"
string[] uncPaths = { @"\\MyMachine.domain1.mycompany.com\C$\ThingsToDo.txt",
                    @"\\MyMachine\c$\ThingsToDo.txt",
                    @"\\MyMachine\d$\documents\mydocument.docx" }

foreach (string uncPath in uncPaths)
{
    printfn "Input string: " + uncPath)
    printfn "Returned string: " + Regex.Replace(uncPath, pattern, replacement))
    printfn )
}
// The example displays the following output if run on a machine whose name is
// MyMachine:
//    Input string: \\MyMachine.domain1.mycompany.com\C$\ThingsToTo.txt
//    Returned string: C:\ThingsToDo.txt
//
//    Input string: \\MyMachine\c$\ThingsToDo.txt
//    Returned string: c:\ThingsToDo.txt
//
//    Input string: \\MyMachine\d$\documents\mydocument.docx
//    Returned string: d:\documents\mydocument.docx

// https://msdn.microsoft.com/en-us/library/taz3ak2f(v=vs.110).aspx

// Get drives available on local computer and form into a single character expression.
string[] drives = Environment.GetLogicalDrives()
string driveNames = String.Empty
foreach (string drive in drives)
    driveNames += drive.Substring(0,1)
// Create regular expression pattern dynamically based on local machine information.
string pattern = @"\\\\" + Environment.MachineName + @"(?:\.\w+)*\\([" + driveNames + @"])\$"

string replacement = "$1:"
string[] uncPaths = { @"\\MyMachine.domain1.mycompany.com\C$\ThingsToDo.txt",
                    @"\\MyMachine\c$\ThingsToDo.txt",
                    @"\\MyMachine\d$\documents\mydocument.docx" }

foreach (string uncPath in uncPaths)
{
    printfn "Input string: " + uncPath)
    printfn "Returned string: " + Regex.Replace(uncPath, pattern, replacement, RegexOptions.IgnoreCase))
    printfn )
}
// The example displays the following output if run on a machine whose name is
// MyMachine:
//    Input string: \\MyMachine.domain1.mycompany.com\C$\ThingsToTo.txt
//    Returned string: C:\ThingsToDo.txt
//
//    Input string: \\MyMachine\c$\ThingsToDo.txt
//    Returned string: c:\ThingsToDo.txt
//
//    Input string: \\MyMachine\d$\documents\mydocument.docx
//    Returned string: d:\documents\mydocument.docx

// https://msdn.microsoft.com/en-us/library/hh194617(v=vs.110).aspx

// Get drives available on local computer and form into a single character expression.
string[] drives = Environment.GetLogicalDrives()
string driveNames = String.Empty
foreach (string drive in drives)
    driveNames += drive.Substring(0,1)
// Create regular expression pattern dynamically based on local machine information.
string pattern = @"\\\\" + Environment.MachineName + @"(?:\.\w+)*\\([" + driveNames + @"])\$"

string replacement = "$1:"
string[] uncPaths = { @"\\MyMachine.domain1.mycompany.com\C$\ThingsToDo.txt",
                    @"\\MyMachine\c$\ThingsToDo.txt",
                    @"\\MyMachine\d$\documents\mydocument.docx" }

foreach (string uncPath in uncPaths)
{
    printfn "Input string: " + uncPath)
    string localPath = null
    try {
    localPath = Regex.Replace(uncPath, pattern, replacement,
                                RegexOptions.IgnoreCase,
                                TimeSpan.FromSeconds(0.5))
    printfn "Returned string: " + localPath)
    }
    catch (RegexMatchTimeoutException) {
    printfn "The replace operation timed out.")
    printfn "Returned string: " + localPath)
    if (uncPath.Equals(localPath))
        printfn "Equal to original path.")
    else
        printfn "Original string: " + uncPath)
    }
    printfn )
}
// The example displays the following output if run on a machine whose name is
// MyMachine:
//    Input string: \\MyMachine.domain1.mycompany.com\C$\ThingsToTo.txt
//    Returned string: C:\ThingsToDo.txt
//
//    Input string: \\MyMachine\c$\ThingsToDo.txt
//    Returned string: c:\ThingsToDo.txt
//
//    Input string: \\MyMachine\d$\documents\mydocument.docx
//    Returned string: d:\documents\mydocument.docx


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.groupnamefromnumber(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

open System
open System.Collections.Generic

let pattern = @"(?<city>[A-Za-z\s]+), (?<state>[A-Za-z]{2}) (?<zip>\d{5}(-\d{4})?)"
let cityLines = [|"New York, NY 10003"; "Brooklyn, NY 11238"; "Detroit, MI 48204";
                    "San Francisco, CA 94109"; "Seattle, WA 98109" |]
let rgx = new Regex(pattern)
let names = new List<string>()
let mutable ctr = 1
let mutable exitFlag = false

while (not exitFlag) do
    let name = rgx.GroupNameFromNumber(ctr)
    if (not (String.IsNullOrEmpty(name))) then
        ctr <- ctr + 1
        names.Add(name)
    else
        exitFlag <- true

for cityLine in cityLines do
    let m = rgx.Match(cityLine)
    if (m.Success) then
        printfn "Zip code %s is in %s, %s."
                        m.Groups.[names.[3]].Value
                        m.Groups.[names.[1]].Value
                        m.Groups.[names.[2]].Value

// The example displays the following output:
//       Zip code 10003 is in New York, NY.
//       Zip code 11238 is in Brooklyn, NY.
//       Zip code 48204 is in Detroit, MI.
//       Zip code 94109 is in San Francisco, CA.
//       Zip code 98109 is in Seattle, WA.

let names' = FsRegEx.groupNames

cityLines
|> Array.iter ()


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.getgroupnumbers(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions
open System

let pattern = @"\b((?<word>\w+)\s*)+(?<end>[.?!])"
let input = "This is a sentence. This is a second sentence."

let rgx = new Regex(pattern)
let groupNumbers = rgx.GetGroupNumbers()

let m = rgx.Match(input)

// does GroupNameFromNumber & inverse need to be option type?
if m.Success then
    printfn "Match: %s" m.Value
    for groupNumber in groupNumbers do
        let name = rgx.GroupNameFromNumber(groupNumber)

        let isNumber, _ = Int32.TryParse(name)

        printfn "   Group %i%s: '%s'"
            groupNumber
            (if (String.IsNullOrEmpty(name) |> not)
                && (not isNumber) then
                " (" + name + ")"
                else String.Empty)
            m.Groups.[groupNumber].Value
else ()

// The example displays the following output:
//       Match: This is a sentence.
//          Group 0: 'This is a sentence.'
//          Group 1: 'sentence'
//          Group 2 (word): 'sentence'
//          Group 3 (end): '.'

let groupNumbers' = FsRegEx.groupNumbers pattern
let groupNames = FsRegEx.groupNames pattern

let m' = FsRegEx.firstMatch pattern input

Array.zip groupNumbers' groupNames
|> Array.iter (fun (n, name) ->
    let isNumber, _ = Int32.TryParse(name)
    printfn "   Group %i%s: '%s'"
        n
        (if (not isNumber) then
            " (" + name + ")"
         else String.Empty)
        (m'.Groups()).[n].Value
    )


text:
// https://msdn.microsoft.com/en-us/library/9ek5zak6(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

let compilationList = new List<RegexCompilationInfo>()

// Define regular expression to detect duplicate words
let expr = new RegexCompilationInfo(@"\b(?<word>\w+)\s+(\k<word>)\b",
            RegexOptions.IgnoreCase || RegexOptions.CultureInvariant,
            "DuplicatedString",
            "Utilities.RegularExpressions",
            true)
// Add info object to list of objects
compilationList.Add(expr)

// Define regular expression to validate format of email address
let expr = new RegexCompilationInfo(@"^(?("")(""[^""]+?""@)|(([0-9A-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9A-Z])@))" +
            @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9A-Z][-\w]*[0-9A-Z]\.)+[A-Z]{2,6}))$",
            RegexOptions.IgnoreCase | RegexOptions.CultureInvariant,
            "EmailAddress",
            "Utilities.RegularExpressions",
            true)
// Add info object to list of objects
compilationList.Add(expr)

// Generate assembly with compiled regular expressions
let compilationArray = new RegexCompilationInfo[compilationList.Count]
let assemName = new AssemblyName("RegexLib, Version=1.0.0.1001, Culture=neutral, PublicKeyToken=null")
compilationList.CopyTo(compilationArray)
Regex.CompileToAssembly(compilationArray, assemName)

// https://msdn.microsoft.com/en-us/library/ew6t47sw(v=vs.110).aspx

let compilationList = new List<RegexCompilationInfo>()

// Define regular expression to detect duplicate words
let expr = new RegexCompilationInfo(@"\b(?<word>\w+)\s+(\k<word>)\b",
            RegexOptions.IgnoreCase | RegexOptions.CultureInvariant,
            "DuplicatedString",
            "Utilities.RegularExpressions",
            true)
// Add info object to list of objects
compilationList.Add(expr)

// Define regular expression to validate format of email address
let expr = new RegexCompilationInfo(@"^(?("")(""[^""]+?""@)|(([0-9A-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9A-Z])@))" +
            @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9A-Z][-\w]*[0-9A-Z]\.)+[zA-Z]{2,6}))$",
            RegexOptions.IgnoreCase | RegexOptions.CultureInvariant,
            "EmailAddress",
            "Utilities.RegularExpressions",
            true)
// Add info object to list of objects
compilationList.Add(expr)

// Apply AssemblyTitle attribute to the new assembly
//
// Define the parameter(s) of the AssemblyTitle attribute's constructor
Type[] parameters = { typeof(string) }
// Define the assembly's title
object[] paramValues = { "General-purpose library of compiled regular expressions" }
// Get the ConstructorInfo object representing the attribute's constructor
ConstructorInfo ctor = typeof(System.Reflection.AssemblyTitleAttribute).GetConstructor(parameters)
// Create the CustomAttributeBuilder object array
CustomAttributeBuilder[] attBuilder = { new CustomAttributeBuilder(ctor, paramValues) }

// Generate assembly with compiled regular expressions
let compilationArray = new RegexCompilationInfo[compilationList.Count]
AssemblyName assemName = new AssemblyName("RegexLib, Version=1.0.0.1001, Culture=neutral, PublicKeyToken=null")
compilationList.CopyTo(compilationArray)
Regex.CompileToAssembly(compilationArray, assemName, attBuilder)

// https://msdn.microsoft.com/en-us/library/5a9btak8(v=vs.110).aspx

// (no sample code)


text:
// https://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.escape(v=vs.110).aspx

#I __SOURCE_DIRECTORY__
#load "load-project-debug.fsx"

open System.Text.RegularExpressions

let pattern = Regex.Escape("[") + "(.*?)]"
let input = "The animal [what kind?] was visible [by whom?] from the window."

let matches = Regex.Matches(input, pattern)
let mutable commentNumber = 0

printfn "%s produces the following matches:" pattern
for match' in matches do
    commentNumber <- commentNumber + 1
    printfn "   %i: %s" commentNumber match'.Value

// This example displays the following output:
//       \[(.*?)] produces the following matches:
//          1: [what kind?]
//          2: [by whom?]

printfn "%s produces the following matches:" pattern

FsRegEx.matches pattern input
|> Array.iteri (fun i x -> printfn "   %i: %s" (i + 1) x.Value)


text:
// Warning: generated file; your changes could be lost when a new file is generated.
#I __SOURCE_DIRECTORY__
#load "load-references-debug.fsx"
#load "../FsRegEx.fsi"
      "../FsRegEx.fs"
      "../VerbalExpressions.fsi"
      "../VerbalExpressions.fs"
      "../CommonFsRegEx.fsi"
      "../CommonFsRegEx.fs"


text:
// Warning: generated file; your changes could be lost when a new file is generated.
#I __SOURCE_DIRECTORY__
#r "System.Core.dll"
#r "System.dll"
#r "System.Numerics.dll"
#r "System.ComponentModel.Composition.dll"
#r "../../../packages/System.ValueTuple/lib/netstandard1.0/System.ValueTuple.dll"