I'm getting my feet wet with Clojure, and trying to get used to functional programming.
I've been translating various imperative functions from other languages into their Clojure equivalents -- and so far everything has been going well. However, I've now run into a sticking point and I have no idea how to translate this Java method into idiomatic Clojure.
At first "map" seemed like the right tool, but after playing with it a bit I'm not so sure. Can someone show me how to write this function in Clojure?
Thanks!
public String calculateChecksum(String str)
{
String hash = "bjytk3lfj%3jklDskj";
int key = 1690912;
for(int i=0; i < str.length(); i++) {
key = key ^ (int)(hash.charAt(i%hash.length()))^(int)(str.charAt(i));
key = key>>>23|key<<9;
}return "8"+toHex8(key>>>(8&255))+toHex8(key&255);
}
We're just past Hallow'een, and it's... the night of the living n00bs!
I have just a few days of Clojure programming under my belt. This effort is closer to "real" Clojure, and at least it compiles. It also produces a result, but probably not the correct one. More after this:
(ns erikcw)
(defn toHex8 [n] (format "%08x" n)) ; Just a guess!
; can't use str, that's predefined.
(defn calculateChecksum [url] ; I renamed the arg to url so I can use strn later.
(loop [strn url ; this will loop over chars in strn.
hash (cycle "bjytk3lfj%3jklDskj") ; now hash repeats for as long as you need it.
key 1690912] ; modifying key along the way.
(prn strn key) ; debug print.
(let [k2 (bit-xor (bit-xor key (int (first hash))) (int (first strn)))
k3 (bit-or (bit-shift-right k2 23) (bit-shift-left k2 9))]
(if (empty? (rest strn))
(str "8" (toHex8 (bit-shift-right k3 8)) (toHex8 (bit-and k3 255)))
(recur (rest strn) (rest hash) k3)))))
(prn (calculateChecksum "HowNowBrownCow"))
I don't know what the toHex8
function does, so I wrote a function that prints its argument as an 8 digit hex number. Just to get the dang thing to compile.
Rather than use an index to pull characters out of hash
and strn
, I treat both as sequences of characters and deal with only their head elements in each iteration. hash
is infinitely long, thanks to (cycle)
.
The bit operations have names starting with "bit-
".
Because integers can become arbitrarily large in Clojure, the resulting number becomes bigger with every character thanks to the << 9
. That's probably not intended.
Anyway, some spoilsport just posted what will probably be a correct answer. Still, this was fun, I hope I managed to share a little of the effort with you.
Edit: Because Dave Ray is insisting on using (reduce)
, I've done another solution:
(defn next-key [key str-hash]
(let [str1 (first str-hash)
hash1 (second str-hash)
k2 (bit-xor (bit-xor key hash1) str1)]
(bit-or (bit-shift-right k2 23) (bit-shift-left k2 9))))
(defn calculateChecksum2 [url]
(let [kk
(reduce next-key 1690912
(partition 2 ; (72 98) (111 106) (119 121) ...
(map int ; 72 98 111 106 119 121
(interleave url (cycle "bjytk3lfj%3jklDskj"))))) ; "HbojwyNt..."
]
(str "8" (toHex8 (bit-shift-right kk 8)) (toHex8 (bit-and kk 255)))))
(prn (calculateChecksum2 "HowNowBrownCow"))
This one is a little easier to read and needs no loop. next-key
could have been dragged inside the main function but I find things easier to understand like this.
We have a list of hash values and one of string values. To make reduce
work I had to crunch them up into a single list; see comments.
We still have the problem that the original algorithm wasn't intended to work with integers of unlimited size, plus a possible parenthesization problem in its last line. You may want to build your own truncating bit-twiddling functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With