Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active April 7, 2020 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/e8d612618a506cead8919c23252019c0 to your computer and use it in GitHub Desktop.
Save ericnormand/e8d612618a506cead8919c23252019c0 to your computer and use it in GitHub Desktop.

Inverse Yoda

Talk like this, Yoda does. Translate back to normal, you must.

(ayoda "Talk like this, Yoda does.") ;=> "Yoda does talk like this."
(ayoda "Translate back to normal, you must") ;=> "You must translate back to normal."
(ayoda "Fun, Clojure is. Learn it, I will.") ;=> "Clojure is fun. I will learn it."
(ayoda "Do or do not. There is no try.") ;=> "Do or do not. There is no try."

Some notes:

  • Expect at most one comma in the sentence. If there is no comma, it doesn't need translation.
  • Try to handle capitals correctly.
  • There may be more than one sentence. Handle all of them.

Thanks to this site for the challenge idea.

NOTE: There was a mistake in the examples in the published newsletter. I have corrected it above.

(require '[clojure.string :refer [includes? split capitalize lower-case]])
(defn invert-sentence [s]
(if (includes? s ", ")
(let [[a b] (split s #", ")]
(str (capitalize b) " " (lower-case a) "."))
(str s ".")))
(defn ayoda [s]
(->> (split s #"\.\s*")
(map invert-sentence)
(interpose " ")
(apply str)))
(ayoda "Talk like this, Yoda does.")
; => "Yoda does talk like this."
(ayoda "Translate back to normal, you must")
; => "You must translate back to normal."
(ayoda "Fun, Clojure is. Learn it, I will.")
; => "Clojure is fun. I will learn it."
(ayoda "Do or do not. There is no try.")
; => "Do or do not. There is no try."
(defn ayoda
[text]
(letfn [(parse [text]
(re-seq #"\s*([^,.]+),?\s*([^.]*)\.?" text))
(translate [[_ before after]]
(-> (str after " " before ".")
clojure.string/trim
clojure.string/capitalize))]
(->> (parse text)
(map translate)
(clojure.string/join " "))))
(ns ayoda
(:require [clojure.string :as str]))
(defn ayoda [s]
(let [sentences (str/split s #"\.|\?|\!")
fragments (map #(str/split % #",") sentences)]
(if ((set s) \,)
(str/trimr
(apply str
(map (fn [fragment]
(str/capitalize
(str (str/trim (second fragment))
" "
(str/trim (first fragment))
". ")))
fragments)))
s)))
(defn reorder
[sentence]
(->> (string/split sentence #", “)
(map #(str (string/trim %) “.”))
(reverse)
(string/join)))
(defn reconstruct
[sentence]
(apply str (->> (string/split sentence #”\.”)
(string/join “ “)
(string/capitalize))
“.”))
(defn ayoda
[yoda-speak]
(->> (map
(fn [sentence]
(->> sentence
reorder
reconstruct))
(string/split yoda-speak #”\.”))
(string/join " “)))
(ayoda "Talk like this, Yoda does.”)
(ayoda "Translate back to normal, you must”)
(ayoda "Fun, Clojure is. Learn it, I will.”)
(ayoda "Do or do not. There is no try.”)
(defn split-trim [re s]
(->> re
(clojure.string/split s)
(map clojure.string/trim)))
(defn ayoda1 [s]
(->> s
(split-trim #",")
reverse
(clojure.string/join " ")
clojure.string/capitalize))
(defn ayoda [s]
(->> s
(split-trim #"\.")
(map ayoda1)
(map #(str % "."))
(clojure.string/join " ")))
(ns yoda
(:require [clojure.string :as str]
[clojure.test :refer [deftest is]]))
(defn- translate-sentence
[sentence]
(let [[x & xs] (seq sentence)]
(as-> (cons (str/lower-case (str x)) xs) s
(apply str s)
(str/split s #",")
(map str/trim s)
(reverse s)
(str/join " " s)
(str (str/capitalize s) "."))))
(defn ayoda
[s]
(->> (str/split s #"\.")
(map translate-sentence)
(str/join " ")))
(deftest yoda-test
(is (= "Yoda does talk like this." (ayoda "Talk like this, Yoda does.")))
(is (= "You must translate back to normal." (ayoda "Translate back to normal, you must.")))
(is (= "Clojure is fun. I will learn it." (ayoda "Fun, Clojure is. Learn it, I will.")))
(is (= "Do or do not. There is no try." (ayoda "Do or do not. There is no try."))))
(ns functional-tv-puzzles.-2020.ayoda-371
(:require [clojure.string :as s]
[clojure.test :as t]))
(defn ayoda [txt]
(let [transform (fn [[beg end :as contents]]
(if end
[(s/capitalize end), (s/lower-case beg)]
contents))
build-sentence (fn [halves]
(->> halves
(interpose " ")
flatten
(apply str)))
link-sentences (fn [sentences]
(->> sentences
(map #(str % "."))
(interpose " ")
(apply str)))]
(->> (s/split txt #"\.\s*" )
(map
#(->> (s/split % #",\s*")
transform
build-sentence))
link-sentences)))
;; Single pass-through
(defn ayoda-2 [txt]
(let [txt (str txt " . ") ;; end-marker
dot? #(re-matches #"\.\s*" %)
comma? #(re-matches #",\s*" %)
;; Raw text -> seq of tokens: words and separators
tokenizing (comp (partition-by #(#{\space \. \,} %))
(map #(apply str %))
(map s/trim)
(filter seq))
;; Tokens -> [<sentence first half str>, <second half str>], or [<single>]
;; One tuple per sentence.
structuring (fn [rf]
(let [init-val [""]
halves (atom init-val)
add-word #(do (swap! halves
(fn [[beg end]]
(if end
[beg (str end % " ")]
[(str beg % " ")])))
(rf %2))
add-half #(do (swap! halves
(fn [[beg]]
[beg ""]))
(rf %))
done #(let [v @halves]
(reset! halves init-val)
(rf % v))]
(completing (fn [acc token]
(cond (dot? token)
(done acc)
(comma? token)
(add-half acc)
:else
(add-word token acc))))))
;; Core task of switching halves and capitalization
transforming (fn [rf]
(completing (fn [acc [beg end :as content]]
(rf acc
(if end
[(s/capitalize end), (s/lower-case beg)]
content)))))
;; Tuples -> sentences
formatting (fn [rf]
(completing (fn [acc [beg end]]
(rf acc
(if end
(str beg (s/trim end) ". ")
(str (s/trim beg) ". "))))))
;; Detect last space using end-narker and remove.
trimming (fn [rf]
(completing (fn [acc txt]
(if (dot? txt)
(rf (s/trim acc))
(rf acc txt)))))]
(transduce (comp tokenizing
structuring
transforming
formatting
trimming) str txt)))
(t/deftest ayoda_test
(t/are [input exp] (= exp (ayoda input) (ayoda-2 input))
"Talk like this, Yoda does."
"Yoda does talk like this."
"Translate back to normal, you must."
"You must translate back to normal."
"Fun, Clojure is. Learn it, I will."
"Clojure is fun. I will learn it."
"Do or do not. There is no try."
"Do or do not. There is no try."
"To be or not to be, what to make of. Nothing or something. So, that is."
"What to make of to be or not to be. Nothing or something. That is so."
))
(require '[clojure.string :as s])
(defn ayoda [ss]
(letfn [(ayoda1 [s1]
(let [[fst sec] (s/split s1 #",")]
(if (nil? sec) (str (s/trim s1) ".")
(str (->> sec s/trim s/capitalize) " "
(->> fst s/trim s/lower-case) "."))))]
(->> (map ayoda1 (s/split ss #"\.")) (s/join \space))))
(ns adv.joda
(:require [clojure.string :refer [split upper-case lower-case join]]))
(defn modify-1st [f s]
(str (f (subs s 0 1)) (subs s 1)))
(defn ayoda-sentence [sentence]
(let [[a b] (split sentence #", ")]
(if b
(str (modify-1st upper-case b) " " (modify-1st lower-case a))
a)))
(defn ayoda [text]
(->> (split (str text " ") #"\. ")
(map ayoda-sentence)
(join ". ")
((fn [s] (str s ".")))))
(defn ayoda [s]
(let [lowerfirst #(str (.toLowerCase (subs % 0 1)) (subs % 1))
upperfirst #(str (.toUpperCase (subs % 0 1)) (subs % 1))]
(->> (clojure.string/split s #"\.\s?")
(map #(clojure.string/split % #","))
(map (fn [[p1 p2]] (if-not p2 p1 (str (upperfirst (.trim p2)) " " (lowerfirst (.trim p1))))))
(map #(str % ". "))
(clojure.string/join)
(clojure.string/trim))))
(ns purelyfunctional-newsletters.issue-371
(:require [clojure.test :refer :all]
[clojure.string :as str]))
(defn- lower-case-first-letter [s]
(if (seq s)
(let [fst (subs s 0 1)
rst (subs s 1)]
(str (str/lower-case fst) rst))
""))
(defn- upper-case-first-letter [s]
(if (seq s)
(let [fst (subs s 0 1)
rst (subs s 1)]
(str (str/upper-case fst) rst))
""))
(defn- sentence-info [s]
(if (or (str/ends-with? s ".")
(str/ends-with? s "?")
(str/ends-with? s "!"))
{:sentence (subs s 0 (dec (count s)))
:sentence-ending (subs s (dec (count s)))}
{:sentence s
:sentence-ending "."}))
(defn- translate-yoda-sentence [sentence]
(if (not (str/includes? sentence ","))
sentence
(let [{sentence :sentence
sentence-ending :sentence-ending} (sentence-info sentence)
phrases (str/split sentence #",")
first-phrase (-> (first phrases) str/trim)
second-phrase (-> (second phrases) str/trim)]
(str (upper-case-first-letter second-phrase)
" "
(lower-case-first-letter first-phrase)
sentence-ending))))
(defn ayoda [s]
(if (or (nil? s)
(not (str/includes? s ",")))
s
(let [sentences (str/split s #"(?<=\.|\?|!)")]
(->> sentences
(map translate-yoda-sentence)
(str/join " ")))))
(deftest ayoda-tests
(is (= nil (ayoda nil)))
(is (= "" (ayoda "")))
(is (= "Hi there!" (ayoda "There, hi!")))
(is (= "Yoda does talk like this."
(ayoda "Talk like this, Yoda does.")))
(is (= "You must translate back to normal."
(ayoda "Translate back to normal, you must.")))
(is (= "Clojure is fun. I will learn it."
(ayoda "Fun, Clojure is. Learn it, I will.")))
(is (= "Do or do not. There is no try."
(ayoda "Do or do not. There is no try."))))
@agrison
Copy link

agrison commented Apr 6, 2020

Hi @ericnormand,

Couldn't find the one I sent to you by mail, so posting it here:

(require '[clojure.string :refer [includes? split capitalize lower-case]])

(defn invert-sentence [s]
  (if (includes? s ", ")
    (let [[a b] (split s #", ")]
      (str (capitalize b) " " (lower-case a) "."))
    (str s ".")))

(defn ayoda [s]
  (->> (split s #"\.\s*")
       (map invert-sentence)
       (interpose " ")
       (apply str)))

(ayoda "Talk like this, Yoda does.")
; => "Yoda does talk like this."

(ayoda "Translate back to normal, you must")
; => "You must translate back to normal."

(ayoda "Fun, Clojure is. Learn it, I will.")
; => "Clojure is fun. I will learn it."

(ayoda "Do or do not. There is no try.")
; => "Do or do not. There is no try."

@ericnormand
Copy link
Author

Hi @agrison,

Sorry I missed your submission. I just added it.

Rock on!
Eric

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment