jappy

String Wildcard Expansion in Clojure

Dec 11th, 2012
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;; first implementation -- kinda naive
  2. (defn expand-wildcards [input-str alphabet-str]
  3.   "Given an input string replaces '?'s with all possible characters as
  4.   expressed in the alphabet string parameter.
  5.  
  6.      ex. user> (expand-wildcards \"1?0110?1\" \"ab\")
  7.          => (1a0110a1 1a0110b1 1b0110a1 1b0110b1)
  8.  
  9.          user> (expand-wildcards \"1?0110?1\" \"abc\")
  10.          => (1a0110a1 1a0110b1 1a0110c1 1b0110a1 1b0110b1 1b0110c1 1c0110a1 1c0110b1 1c0110c1)"
  11.   (loop [expansion (seq [input-str])
  12.          times (count (filter #(= % \?) (seq input-str)))]
  13.     (if (= times 0)
  14.       expansion
  15.       (recur (mapcat
  16.               (fn [expand]
  17.                 (map #(.replaceFirst expand "\\?" (str %))
  18.                      (seq alphabet-str)))
  19.               expansion)
  20.              (dec times)))))
  21.  
  22. ;;; testing
  23.  
  24. ;(count (expand-wildcards "1?011????" "abcdefghijklmnopqrstuvwxyz"))
  25. ;(count (expand-wildcards "1?011????" "abc"))
  26. ;(println (expand-wildcards "1?0110?1" "ab"))
  27. ;(println (expand-wildcards "1?0110?1" "abc"))
  28.  
  29. ;;;;;;;;;;;;;;;;;; Alternative Implementations ;;;;;;;;;;;;;;;;;;;
  30.  
  31. (defn to-word [ith-word pad alphabet]
  32.   "Returns the ith word of pad length given an alphabet.
  33.  
  34.     ex. user> (to-word 5 5 \"abc\")
  35.         => \"aaabc\"
  36.  "
  37.   (let [alphabet-size (count alphabet)]
  38.     (loop [quotient ith-word
  39.            word nil]
  40.       (if (< quotient 1)
  41.         (if (< (count word) pad)
  42.           (apply str (concat (repeat (- pad (count word))
  43.                                      (.charAt alphabet 0))
  44.                              word))
  45.           (apply str word))
  46.         (recur (quot quotient alphabet-size)
  47.                (cons (.charAt alphabet (rem quotient alphabet-size)) word))))))
  48.  
  49. (defn fill-wildcards [input fill]
  50.   "Given an input string and a fill string, wildcards in the input string
  51.   will be replaced with characters from the fill string."
  52.   (loop [input-pos (dec (count input))
  53.          fill-pos (dec (count fill))
  54.          result nil]
  55.     (if (< input-pos 0)
  56.       (apply str result)
  57.       (let [current-char (.charAt input input-pos)
  58.             wildcard? (= \? current-char)]
  59.         (recur (dec input-pos)
  60.                (if wildcard?
  61.                  (dec fill-pos)
  62.                  fill-pos)
  63.                (cons (if wildcard?
  64.                        (.charAt fill fill-pos)
  65.                        current-char) result))))))
  66.  
  67. ;; second impl - a bit different approach... working towards laziness
  68. (defn expand-wildcards [input-str alphabet]
  69.   "Given an input string replaces '?'s with all possible characters as
  70.   expressed in the alphabet string parameter.
  71.  
  72.      ex. user> (expand-wildcards \"1?0110?1\" \"ab\")
  73.          => (1a0110a1 1a0110b1 1b0110a1 1b0110b1)
  74.  
  75.          user> (expand-wildcards \"1?0110?1\" \"abc\")
  76.          => (1a0110a1 1a0110b1 1a0110c1 1b0110a1 1b0110b1 1b0110c1 1c0110a1 1c0110b1 1c0110c1)"
  77.   (let [expansion (seq [input-str])
  78.         num-wildcards (count (filter #(= % \?) (seq input-str)))
  79.         alphabet-size (count alphabet)
  80.         num-results (Math/pow alphabet-size num-wildcards)]
  81.     (map #(fill-wildcards input-str (to-word % num-wildcards alphabet)) (range 0 (long num-results)))))
  82.  
  83. ;; this version is lazy
  84. (defn expand-wildcards [input-str alphabet num-to-generate]
  85.   "Given an input string replaces '?'s with all possible characters as
  86.   expressed in the alphabet string parameter.
  87.  
  88.      ex. user> (expand-wildcards \"1?0110?1\" \"ab\" 3)
  89.          => (1a0110a1 1a0110b1 1b0110a1)
  90.  
  91.          user> (expand-wildcards \"1?0110?1\" \"abc\" 5)
  92.          => (1a0110a1 1a0110b1 1a0110c1 1b0110a1 1b0110b1)"
  93.   (lazy-seq
  94.    (let [expansion (seq [input-str])
  95.          num-wildcards (count (filter #(= % \?) (seq input-str)))
  96.          alphabet-size (count alphabet)
  97.          num-results (Math/pow alphabet-size num-wildcards)
  98.          f (fn [num] (fill-wildcards input-str (to-word num num-wildcards alphabet)))]
  99.      (when-let [s (seq (range 0 (long num-to-generate)))]
  100.        (cons (f (first s)) (map f (rest s)))))))
  101.  
  102. ;(take 10 (expand-wildcards "1?011????" "abcdefghijklmnopqrstuvwxyz" 50))
Advertisement
Add Comment
Please, Sign In to add comment