Regular Expressions in Elm

Our first program demonstrates how to work with regular expressions in Elm. Here’s the full source code:

module Main exposing (main)

import Html exposing (Html, div, text)
import Regex

main : Html msg
main =
    div []
        [ testMatchString
        , testFindString
        , testFindStringIndex
        , testFindStringSubmatch
        , testFindAllString
        , testReplace
        ]

testMatchString : Html msg
testMatchString =
    let
        pattern =
            "p([a-z]+)ch"

        testString =
            "peach"

        match =
            Regex.contains (Maybe.withDefault Regex.never (Regex.fromString pattern)) testString
    in
    div [] [ text ("Match: " ++ Debug.toString match) ]

testFindString : Html msg
testFindString =
    let
        pattern =
            "p([a-z]+)ch"

        testString =
            "peach punch"

        result =
            Regex.find (Maybe.withDefault Regex.never (Regex.fromString pattern)) testString
                |> List.head
                |> Maybe.map .match
                |> Maybe.withDefault ""
    in
    div [] [ text ("Find: " ++ result) ]

testFindStringIndex : Html msg
testFindStringIndex =
    let
        pattern =
            "p([a-z]+)ch"

        testString =
            "peach punch"

        result =
            Regex.find (Maybe.withDefault Regex.never (Regex.fromString pattern)) testString
                |> List.head
                |> Maybe.map (\match -> "idx: " ++ String.fromInt match.index ++ " " ++ String.fromInt (match.index + String.length match.match))
                |> Maybe.withDefault ""
    in
    div [] [ text result ]

testFindStringSubmatch : Html msg
testFindStringSubmatch =
    let
        pattern =
            "p([a-z]+)ch"

        testString =
            "peach punch"

        result =
            Regex.find (Maybe.withDefault Regex.never (Regex.fromString pattern)) testString
                |> List.head
                |> Maybe.map .submatches
                |> Maybe.withDefault []
                |> List.filterMap identity
    in
    div [] [ text ("Submatches: " ++ Debug.toString result) ]

testFindAllString : Html msg
testFindAllString =
    let
        pattern =
            "p([a-z]+)ch"

        testString =
            "peach punch pinch"

        result =
            Regex.find (Maybe.withDefault Regex.never (Regex.fromString pattern)) testString
                |> List.map .match
    in
    div [] [ text ("All matches: " ++ Debug.toString result) ]

testReplace : Html msg
testReplace =
    let
        pattern =
            "p([a-z]+)ch"

        testString =
            "a peach"

        result =
            Regex.replace (Maybe.withDefault Regex.never (Regex.fromString pattern)) (\_ -> "<fruit>") testString
    in
    div [] [ text ("Replace: " ++ result) ]

In this Elm program, we demonstrate various regular expression operations:

  1. We test if a pattern matches a string using Regex.contains.
  2. We find the first match of a pattern in a string using Regex.find and extract the matched string.
  3. We find the index of the first match using Regex.find and extract the index information.
  4. We extract submatches (captured groups) from the first match.
  5. We find all matches of a pattern in a string.
  6. We use Regex.replace to replace matches with a new string.

Note that Elm’s regular expression functions are different from Go’s. Elm uses a Regex type and most operations are performed using the Regex.find function, which returns a list of Match records. We then process these records to extract the desired information.

Also, Elm requires handling the possibility of an invalid regex pattern, which is why we use Maybe.withDefault Regex.never (Regex.fromString pattern) when creating regex patterns.

To run this program, you would typically compile it to JavaScript and run it in a browser, or use an Elm development environment like elm-reactor.

Remember that Elm is a functional language and its approach to regular expressions is quite different from imperative languages like Go. The concepts are similar, but the implementation details and API differ significantly.