A few times in my career I've worked on small modules that generated random/unique alphanumeric codes. Most recently, the module in question was written in Clojure, something like the code below.
(def ambiguous-characters #{\O \0 \1 \I})
(def alphabet (map char (range (int \A) (inc (int \Z)))))
(def code-chars
(->> (concat alphabet (range (int \0) (inc (int \9))))
(map char)
(remove ambiguous-characters)))
(defn unique-readable-code [length]
(->> (repeatedly #(rand-nth code-chars))
(take length)
(apply str)))
That code creates things like this:
user=> (unique-readable-code 10)
"EYN2N5EE7K"
There was a mechanism already in place to prevent objectionable words from being generated, something like the following:
(require 'clojure.string)
(def bad-words (map rot13 ["SHUCKS" "DARN" "HECK"]))
(defn has-bad-word? [code]
(some #(clojure.string/includes? code %) bad-words))
(defn infinite-list-of-codes [len]
(->> (repeatedly #(unique-readable-code len))
(remove has-bad-word?)))
So you could easily generate lots of codes:
user=> (take 9 (infinite-list-of-codes 10))
("WDJG7ZSE26" "4PE53YWLUD" "M9LWZMPHXA"
"N3ZJT2Q3EC" "7SZEQGG8TS" "MALAWR6ZA2"
"QLN4RA2K8A" "Q939Q7DXJ8" "VCP4NVQTKY")
Well, I got tired of looking at the actual list of bad-words
, which was much longer and much more objectionable than the list shown above. So, I decided to encode it using rot-13.
(def rot13-translations
(->> (cycle alphabet)
(drop 13)
(take 26)
(zipmap alphabet)))
(defn rot13 [text]
(->> (clojure.string/upper-case text)
(replace rot13-translations)
(apply str)))
Rot-13 has a cyclical quality, meaning that calling it once encodes, calling it again with the output of the first call decodes.
user=> (rot13 "A")
"N"
user=> (rot13 (rot13 "A"))
"A"
Put it all together and you have a nice way to remove objectionable words without needing to see them (except to add new ones).
(require 'clojure.string)
(def alphabet (map char (range (int \A) (inc (int \Z)))))
(def rot13-translations
(->> (cycle alphabet)
(drop 13)
(take 26)
(zipmap alphabet)))
(defn rot13 [text]
(->> (clojure.string/upper-case text)
(replace rot13-translations)
(apply str)))
; Paste this definition into a REPL to view current listing.
; Use the rot13 fn above to encode additional words.
(def bad-words (map rot13 ["FUHPXF" "QNEA" "URPX"]))
(defn has-bad-word? [code]
(some #(clojure.string/includes? code %) bad-words))
(def code-chars
(->> (concat alphabet (range (int \0) (inc (int \9))))
(map char)
(remove #{\O \0 \1 \I})))
(defn unique-readable-code [length]
(->> (repeatedly #(rand-nth code-chars))
(take length)
(apply str)))
(defn infinite-list-of-codes [len]
(->> (repeatedly #(unique-readable-code len))
(remove has-bad-word?)))
;;;;;;;;;;;;;;;;;;;;;;;
(it "rot13"
(let [input "INPUT"]
(should-not= input (->> input codes/rot13))
(should= input (->> input codes/rot13 codes/rot13))))
(it "identifies bad words"
(let [code (codes/rot13 "URYY")]
(should (codes/has-bad-word? code))))