Share via


F# String extension methods rather than using RegEx

In my previous post I talked about some extension methods for string checking:

https://blogs.msdn.com/b/carlnol/archive/2011/10/19/string-extension-methods-rather-than-using-regex.aspx

But what would be a post if there was not a F# equivalent.

Interestingly the ability to perform checks on each character in a string is actually already supported by F#; using the String.forall:

String.forall Char.IsLetter "AO"

However, one can also easily create the same String extension methods, as in the previous post, in F#:

namespace FSharp.StringExtensions

open System
open Microsoft.FSharp.Core

module StringAllChecks =
    
    // private methods to perform the comparisions
    let private isAllValidation (value:string) (charFunc:char -> bool) (length:int option) =

        let stringLength = defaultArg length 0
        if (stringLength < 0) then invalidArg "length" (sprintf "Length must be positive but was %d." length.Value)

        if (String.IsNullOrWhiteSpace(value)) then
            false
        elif (not (String.forall charFunc value)) then
            false
        elif (stringLength > 0 && value.Length <> stringLength) then
            false
        else
            true

    type String with

        member this.IsAllLetter(?length:int) =
            isAllValidation this Char.IsLetter length

        member this.IsAllDigit(?length:int) =
            isAllValidation this Char.IsDigit length

        member this.IsAllLetterOrDigit(?length:int) =
            isAllValidation this Char.IsLetterOrDigit length

        member this.IsAllNumber(?length:int) =
            isAllValidation this Char.IsNumber length

        member this.IsAllLower(?length:int) =
            isAllValidation this Char.IsLower length

        member this.IsAllUpper(?length:int) =
                isAllValidation this Char.IsUpper length

The extension methods are more explicit in F#, compared to the C# implementation, as one merely extends the appropriate type; in this case String.

One of the main differences between this and the C# implementation is around the use of String.forall method rather than the LINQ IEnumerable<T>.All method. Also, an option parameter is used for the string length specification.

These extensions methods allow one to write statements such as:

let trueAllLetter = "AO".IsAllLetter()
let trueAllDigit = "12".IsAllLetter()

let falseAllLetter = "A0".IsAllLetter()
let falseAllDigit = "O1".IsAllLetter()

The main downside to the F# implementation is that the extension methods can only be consumed from F#.