Strings and Regular Expressions
Prerequisites: Strings and characters
A regex literal is written #"..." — backslashes don't need doubling,
so #"\d+" means "one or more digits". It compiles to a Java
java.util.regex.Pattern.
(println (re-find #"\d+" "order 66 shipped")) ; first match
(println (re-matches #"\d{3}-\d{4}" "555-1234")) ; whole string must match
(println (re-matches #"\d{3}-\d{4}" "call 555-1234"))
(println (re-seq #"\d+" "1 fish, 22 fish, 333 fish")) ; all matches
(println (re-find #"(\w+)@(\w+)\.com" "mail ada@example.com"))
(println (re-pattern (str "^" "v" "\\d+$")))
66
555-1234
nil
(1 22 333)
[ada@example.com ada example]
#"^v\d+$"
re-findreturns the first match — or, if the pattern has groups, a vector[whole-match group1 group2 ...].re-matchesrequires the entire string to match.re-seqreturns a lazy sequence of all matches.re-patternbuilds a pattern from a string (then backslashes must be doubled).
Try patterns interactively with the Regex Tester.
Parsing with groups
(def log-line "2026-09-29 ERROR [db] connection lost")
(when-let [[_ date level source msg] (re-matches #"(\S+) (\w+) \[(\w+)\] (.*)" log-line)]
(println {:date date :level (keyword (clojure.string/lower-case level))
:source source :message msg}))
(println (for [[_ id status] (re-seq #"#(\d+) (\w+)" "#123 shipped, #456 pending")]
{:id (parse-long id) :status (keyword status)}))
{:date 2026-09-29, :level :error, :source db, :message connection lost}
({:id 123, :status :shipped} {:id 456, :status :pending})
when-let binds a name and runs its body only if the value is truthy —
perfect for "if it matched, destructure the groups".
Replacing and splitting
(require '[clojure.string :as str])
(println (str/replace "hello world" #"o" "0"))
(println (str/replace "2026-09-29" #"(\d+)-(\d+)-(\d+)" "$3.$2.$1"))
(println (str/replace "hello clojure world" #"\b\w" str/upper-case))
(println (str/split "a1b22c333" #"\d+"))
(println (str/split "one two three" #"\s+"))
(println (str/split-lines "first\nsecond\r\nthird"))
(println (str/replace-first "a-b-c" "-" "+"))
hell0 w0rld
29.09.2026
Hello Clojure World
[a b c]
[one two three]
[first second third]
a+b-c
str/replace takes a string, a regex with $1-style group references,
or a function that receives each match and returns its replacement.
Common mistakes
re-matchesvs.re-find: usere-matchesfor validation, so"abc123"doesn't pass a digits-only check.- Case-insensitive matching needs the
(?i)flag:#"(?i)error".
Practice
Extract all email addresses from
"Contact ada@example.com or ops@test.org today" and print their
domains.
Show solution
(def text "Contact ada@example.com or ops@test.org today")
(def emails (re-seq #"[\w.]+@[\w.]+\w" text))
(println emails)
(println (map #(second (clojure.string/split % #"@")) emails))
(ada@example.com ops@test.org)
(example.com test.org)