Strings and regular expressions
BasicStrings in Clojure are plain JVM/JS strings, but clojure.string ships a
small, consistent vocabulary for working with them — every function takes the
string as its first argument, so they thread cleanly with ->clojure.core/->Thread the value through forms by inserting it as the first arg.view on clojuredocs →. Regular
expressions are literal values written #"…"; four core functions
(re-findclojure.core/re-findFirst match of regex in s; returns string or vector with groups, or nil.view on clojuredocs →, re-matchesclojure.core/re-matchesMatch only if regex matches the entire string.view on clojuredocs →, re-seqclojure.core/re-seqLazy seq of every regex match in s.view on clojuredocs →, re-patternclojure.core/re-patternCompile a regex from a string at runtime.view on clojuredocs →) cover almost every use.
strclojure.core/strConcatenate the print representation of each argument.view on clojuredocs → and the clojure.string toolkit
strclojure.core/strConcatenate the print representation of each argument.view on clojuredocs → is clojure.core's string builder — it concatenates the print
representations of its arguments. Use it instead of +:
The clojure.string namespace adds the common transformations. Each takes
the string as its first argument so the threading macro ->clojure.core/->Thread the value through forms by inserting it as the first arg.view on clojuredocs → chains them
naturally. In a real namespace you'd (:require [clojure.string :as str]) and
write str/trim; in the snippets below we use the fully qualified name so
each REPL block stays self-contained:
A short tour of the ones you'll reach for first:
splitclojure.string/splitSplit s by a regex into a vector of substrings.view on clojuredocs → and joinclojure.string/joinConcatenate a coll into a string, optionally with a separator.view on clojuredocs → are inverse operations: cut a string into a vector of substrings on a separator (regex), or glue a collection back together with one:
replaceclojure.string/replaceReplace matches of match in s; match can be a string, regex, or char.view on clojuredocs → rewrites all matches of a pattern. The pattern can be a literal string or a regex; the replacement can be a string or a function of the match:
replace-firstclojure.string/replace-firstLike replace, but only the first match.view on clojuredocs → does the same but stops at the first match.
Regex literals — #"…"
#"…" is the Clojure reader's syntax for a compiled regex. The pattern
inside is a normal regex string — backslashes need not be doubled inside the
#"…" form when written in source code, but inside a JSON/MDX literal you
do need to double them, which is why the examples above use \\d+
instead of \d+.
Four core functions consume a regex:
- re-findclojure.core/re-findFirst match of regex in s; returns string or vector with groups, or nil.view on clojuredocs → — return the first match (or nil), as a string or vector when groups are present.
- re-matchesclojure.core/re-matchesMatch only if regex matches the entire string.view on clojuredocs → — return a match only if the regex matches the entire string. Useful for validation.
- re-seqclojure.core/re-seqLazy seq of every regex match in s.view on clojuredocs → — return a lazy seq of all matches.
- re-patternclojure.core/re-patternCompile a regex from a string at runtime.view on clojuredocs → — build a regex from a string at runtime (rare; literals cover almost every case).
When the regex has capture groups, re-findclojure.core/re-findFirst match of regex in s; returns string or vector with groups, or nil.view on clojuredocs → and re-matchesclojure.core/re-matchesMatch only if regex matches the entire string.view on clojuredocs → return a vector: the whole match is index 0, then each group:
This pairs beautifully with destructuring:
Practical example: tokenize and tally
Pull words out of a sentence, lowercase them, and count occurrences. Pure seq + string work, no loops:
re-seqclojure.core/re-seqLazy seq of every regex match in s.view on clojuredocs → turns the string into a lazy seq of words, frequenciesclojure.core/frequenciesBuild a map of x → count of occurrences in coll.view on clojuredocs → builds the count map, and the threading reads top-to-bottom.
Check yourself
? quiz
What is the difference between `re-find` and `re-matches`?
Exercise
Write a function domain-of that extracts the domain from an email address,
returning nil when the input isn't a valid email. Use re-matchesclojure.core/re-matchesMatch only if regex matches the entire string.view on clojuredocs → so that
strings like "ada@example.com extra" are rejected.