Alan Thompson
Alan Thompson

Reputation: 29966

When using regular expressions in Clojure or Java, how can I use named capture groups?

Since Java 7, named capture groups have been supported. However, the built-in Clojure functions re-matches, re-find, and re-groups do not allow access to the capture groups by name.

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(dotest
  ; Define a phone number pattern with some named capture groups.
  ; The reader literal #"..." allows us to avoid double-backslash like
  ; we'd need if using the form `(re-pattern <string>)`
  (let [patt #"(?<area>\d{3})-(?<prefix>\d{3})-(?<tail>\d{4})"]
    (is= java.util.regex.Pattern (type patt))

    ; `re-matches` will find the capture groups and stick them in a vector
    ; after the full match The capture groups are numbered starting with 1.
    ; The full match is like group zero.
    (is= ["619-239-5464" "619" "239" "5464"] (re-matches patt "619-239-5464"))

    ; Construct a java.util.regex.Matcher.  Keep in mind that it is a mutable object!
    (let [matcher (re-matcher patt "619-239-5464")]
      ; Execute the Matcher via `re-find`. It returns all 4 groups and caches them
      (is= ["619-239-5464" "619" "239" "5464"] (re-find matcher))

      ; `re-groups` simply returns the cached result from the Matcher
      (is= ["619-239-5464" "619" "239" "5464"] (re-groups matcher))

How can I use named capture groups in a regex from Clojure?

Upvotes: 2

Views: 267

Answers (1)

Alan Thompson
Alan Thompson

Reputation: 29966

The class java.util.regex.Matcher supports named capture groups, but you need to use Java interop to get at them. An example:

; We need the instance function Matcher.group( <name> ) to extract named groups
(is= "619" (.group matcher "area"))
(is= "239" (.group matcher "prefix"))
(is= "5464" (.group matcher "tail"))))

The above code is based on this template project.

Upvotes: 3

Related Questions