开发者

Help translating this Java codeblock to Clojure?

开发者 https://www.devze.com 2022-12-11 19:48 出处:网络
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

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.


Clojure does not expose the >>> operator, so a direct translation is not possible.

0

精彩评论

暂无评论...
验证码 换一张
取 消