# An acronym capitalization checker with regex

**URL:** https://clojureverse.org/t/an-acronym-capitalization-checker-with-regex/8013
**Category:** Watercooler
**Created:** [August 8, 2021, 1:33pm UTC](https://clojureverse.org/t/an-acronym-capitalization-checker-with-regex/8013 "2021-08-08T13:33:29Z")
**Posts on this page:** 1
**Showing post:** 4

<div class="post-metadata">

### Author: ![camdez](https://clojureverse.org/user_avatar/clojureverse.org/camdez/32/1373_2.png) [@camdez](https://clojureverse.org/u/camdez)
#### Post date: [August 8, 2021, 6:45pm UTC](https://clojureverse.org/t/an-acronym-capitalization-checker-with-regex/8013/4 "2021-08-08T18:45:24Z")

</div>

> [@camdez](#):
>
> if you wanted to, you can take that a step further by optimizing it by unifying the common prefixes of the regexes. Could be a fun bit of code to write!

I decided to take a stab an implementing this since it seemed like a fun little challenge:

```clj
(ns camdez.re-opt
  (:require [clojure.walk :as walk]
            [clojure.string :as str]))

;; Convert strings to a graph (nested maps) representing common prefix
;; strings:
;;
;; A -> B -> C
;; -> O -> U -> T
;; -> P -> P -> L -> E
;;
;; Then collapse tails into strings and branches into regex
;; alternations.
(defn- re-literal-opts-str [opts]
  (->> opts
       (reduce (fn [acc s]
                 (assoc-in acc (butlast s) {(last s) nil}))
               {})
       (walk/postwalk (fn [x]
                        (cond
                          (not (map? x)) x
                          (= 1 (count x)) (apply str (first x))
                          :else (str "(?:" (str/join "|" (map (fn [[k v]] (str k v)) x)) ")"))))))

(defn re-literal-opts
  "Builds an optimized regular expression for matching any of the string
  literals in `opts`."
  [opts]
  (re-pattern (re-literal-opts-str opts)))

(defn re-literal-word-opts
  "Builds an optimized regular expression for matching any of the string
  literals in `opts` at word boundaries."
  [opts]
  (re-pattern (str "\\b(?:" (re-literal-opts-str opts) ")\\b")))

```

```clj
;;; Examples

(def sample-opts ["ABC" "ABOUT" "APPLE" "BOTTLE"])

(re-literal-opts-str sample-opts)
;; => "(?:A(?:B(?:C|OUT)|PPLE)|BOTTLE)"

(def p1 (re-literal-opts sample-opts))

(re-seq p1 "WHAT ABOUT BOTTLES? A BOTTLE?")
;; => ("ABOUT" "BOTTLE" "BOTTLE")

(def p2 (re-literal-word-opts sample-opts))

(re-seq p2 "WHAT ABOUT BOTTLES? A BOTTLE?")
;; => ("ABOUT" "BOTTLE")

```

Pretty happy with how it turned out. Only about 20 minutes of work given the magic of Clojure. 🧙

---

_[View the full topic](https://clojureverse.org/t/an-acronym-capitalization-checker-with-regex/8013)._
