String.Regex

A library for working with regex. The syntax matches the RegExp library from JavaScript.

Create

type Regex

A regular expression as specified in JavaScript.

fromString : String -> Maybe Regex

Try to create a Regex. Not all strings are valid though, so you get a `Maybe' back. This means you can safely accept input from users.

import String.Regex as Regex

lowerCase : Regex.Regex
lowerCase =
  Maybe.withDefault Regex.never <|
    Regex.fromString "[a-z]+"

Note: There are some shorthand character classes like \w for word characters, \s for whitespace characters, and \d for digits. Make sure they are properly escaped! If you specify them directly in your code, they would look like "\\w\\s\\d".

fromStringWith : Options -> String -> Maybe Regex

Create a Regex with some additional options. For example, you can define fromString like this:

import String.Regex as Regex

fromString : String -> Maybe Regex.Regex
fromString string =
  fromStringWith { caseInsensitive = False, multiline = False } string
type alias Options = { caseInsensitive : Bool, multiline : Bool }
never : Regex

A regular expression that never matches any string.

Use

contains : Regex -> String -> Bool

Check to see if a Regex is contained in a string.

import String.Regex as Regex

digit : Regex.Regex
digit =
  Maybe.withDefault Regex.never <|
    Regex.fromString "[0-9]"

-- Regex.contains digit "abc123" == True
-- Regex.contains digit "abcxyz" == False
split : Regex -> String -> Array String

Split a string. The following example will split on commas and tolerate whitespace on either side of the comma:

import String.Regex as Regex

comma : Regex.Regex
comma =
  Maybe.withDefault Regex.never <|
    Regex.fromString " *, *"

-- Regex.split comma "tom,99,90,85"     == ["tom","99","90","85"]
-- Regex.split comma "tom, 99, 90, 85"  == ["tom","99","90","85"]
-- Regex.split comma "tom , 99, 90, 85" == ["tom","99","90","85"]

If you want some really fancy splits, a library like gren-lang/parser will probably be easier to use.

find : Regex -> String -> Array Match

Find matches in a string:

import String.Regex as Regex

location : Regex.Regex
location =
  Maybe.withDefault Regex.never <|
    Regex.fromString "[oi]n a (\\w+)"

places : Array Regex.Match
places =
  Regex.find location "I am on a boat in a lake."

-- map .match      places == [ "on a boat", "in a lake" ]
-- map .submatches places == [ [Just "boat"], [Just "lake"] ]

If you need submatches for some reason, a library like gren-lang/parser will probably lead to better code in the long run.

replace : Regex -> (Match -> String) -> String -> String

Replace matches. The function from Match to String lets you use the details of a specific match when making replacements.

import String.Regex as Regex

userReplace : String -> (Regex.Match -> String) -> String -> String
userReplace userRegex replacer string =
  case Regex.fromString userRegex of
    Nothing ->
      string

    Just regex ->
      Regex.replace regex replacer string

devowel : String -> String
devowel string =
  userReplace "[aeiou]" (\_ -> "") string

-- devowel "The quick brown fox" == "Th qck brwn fx"

reverseWords : String -> String
reverseWords string =
  userReplace "\\w+" (.match >> String.reverse) string

-- reverseWords "deliver mined parts" == "reviled denim strap"
type alias Match =
{ match : String
, index : Int
, number : Int
, submatches : Array (Maybe String)
}

The details about a particular match:

  • match — the full string of the match.
  • index — the index of the match in the original string.
  • number — if you find many matches, you can think of each one as being labeled with a number starting at one. So the first time you find a match, that is match number one. Second time is match number two. This is useful when paired with replace if replacement is dependent on how many times a pattern has appeared before.
  • submatches — a Regex can have subpatterns, sup-parts that are in parentheses. This is a array of all these submatches. This is kind of garbage to use, and using a package like gren-lang/parser is probably easier.

Fancier Uses

splitAtMost : Int -> Regex -> String -> Array String

Just like split but it stops after some number of matches.

A library like gren-lang/parser will probably lead to better code in the long run.

findAtMost : Int -> Regex -> String -> Array Match

Just like find but it stops after some number of matches.

A library like gren-lang/parser will probably lead to better code in the long run.

replaceAtMost : Int -> Regex -> (Match -> String) -> String -> String

Just like replace but it stops after some number of matches.

A library like gren-lang/parser will probably lead to better code in the long run.