user=> (char 65)
\A
user=> (char 97)
\a
user=> (str (char 65))
"A"
user=> (str (char 97))
"a"
These are the characters from the ascii decimal values ...
How do I get the ascii decimal values from the characters?
A character is a number, it's just that clojure is showing it to you as a char. The easiest way is to just cast that char to an int.
e.g.
user=> (int \A)
65
user=> (int (.charAt "A" 0))
65
user=> (doseq [c "aA"] (printf "%d%n" (int c)))
97
65
nil
user=> (map int "aA");;
(97 65)
user=> (apply str (map char [97 65]))
"aA"
Related
I'm working through the 4clojure problems. I came across this answer for #120, which I would have totally never thought of on my own:
(fn sum-square [coll]
(let [digits (fn [n] (map #(- (int %) 48) (str n)))
square #(* % %)
sum-digits (fn [n] (reduce + (map square (digits n))))]
(count (filter #(< % (sum-digits %)) coll))))
The part I'm really trying to understand is how the digits part of it works.
(fn [n] (map #(- (int %) 48) (str n))
I'm really confused about how
(map #(- (int %) 48) "10")
returns
(1 0)
Can you please explain how this works? I'm confused about why n has to be turned into a string, and why it's then turned back into an integer, and why it has 48 subtracted. I'm sure there must be some really neat trick I'm missing.
Thanks!
"10" in the context of map can be treated as a seq of chars(in this case \1 and \0)
then int converts say \1 to ascii 49, and \0 to ascii 48
then - 48 converts 49 to 1 and 48 to 0
The aim is to play with a slight modification of the Caesar cipher.
First a function to move a character:
(defn move-char [c shift idx encode-or-decode]
(let [ch (int c) val (mod (* encode-or-decode (+ shift idx)) 26)]
(cond
(and (>= ch (int \A)) (<= ch (int \Z))) (char (+ (mod (+ val (- (int ch) (int \A))) 26) (int \A)))
(and (>= ch (int \a)) (<= ch (int \z))) (char (+ (mod (+ val (- (int ch) (int \a))) 26) (int \a)))
:else c)))
Then a function to map the last one to a string:
(defn move-shift-aux [str shift encode-or-decode]
(map-indexed (fn [idx item] (move-char item shift idx encode-or-decode)) str))
`(move-shift-aux "I should have known..." 1 1)` returns
(\J \space \v \l \t \a \s \l \space \r \l \h \r \space \z \d \f \o \g \. \. \.)
and if I write:
(apply str (move-shift-aux "I should have known..." 1 1))
I get what I want:
"J vltasl rlhr zdfog..."
But if I define:
(defn moving-shift [str shift]
(apply str (move-shift-aux str shift 1)))
(moving-shift "I should have known..." 1)
I get:
CompilerException java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn, compiling:(caesar\core.clj:29:44)
I don't understand why the compiler exception while it does work fine when applying directly.
You're shadowing the str symbol from clojure.core with your str parameter. Inside moving-shift's scope, str refers to "I should have known..." and not clojure.core/str, hence when you call your apply function, you get a ClassCastException, stating that a string is not a function.
Use another name for your string parameter.
I want to do this in Clojure:
int i=1;j=2;k=3;
str r;
cin>>r;
if(r=="A")
cout<<i; (i.e., print 1)
if(r=="J")
cout<<j; (i.e., print 2)
if(r=="K")
cout<<k; (i.e., print 3)
else
do something else
I am doing it like this in clojure:
(defn str-to-num [c]
(if ( = (str (first c )) "A")
1
(java.lang.Integer/valueOf (str (first c))))
(if ( = (str (first c )) "J")
2
(java.lang.Integer/valueOf (str (first c))))
(if ( = (str (first c )) "K")
3
(java.lang.Integer/valueOf (str (first c))))
)
But, I'm getting an error. Could someone tell what I'm doing wrong?
All of the if blocks are run, one after the other, regardless of what any of them return. If you want if / else / chaining you should use cond or case (though the two branches of a standard if work fine if there are only two options).
Your first two if blocks can't do anything meaningful except throw an error. And that is exactly what will happen for most inputs.
"A", "J", and "K" are not valid numbers, so trying to parse them will throw an error.
The only meaningful things this function can do is return the first letter of a string as a number if it is parsible as one.
user> (str-to-num "A")
NumberFormatException For input string: "A" java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)
user> (str-to-num "J")
NumberFormatException For input string: "J" java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)
user> (str-to-num "K")
NumberFormatException For input string: "K" java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)
user> (str-to-num "100")
1
perhaps you wanted something like:
user> (defn str-to-num [c]
(case (first c)
\A 1
\J 2
\K 3
(int (first c))))
#'user/str-to-num
user> (str-to-num "A")
1
user> (str-to-num "J")
2
user> (str-to-num "K")
3
user> (str-to-num "L")
76
user> (str-to-num "☃")
9731
Alternately:
user> (defn str-to-num [c]
(case (first c)
\A 1
\J 2
\K 3
(Integer/parseInt (subs c 0 1))))
#'user/str-to-num
user> (str-to-num "9")
9
The problem is with the form of your if statement
You have
(if ( = (str (first c )) "A")
1
(java.lang.Integer/valueOf (str (first c))))
The form of if is
(if (cond)
trueResult
falseResult)
So your "working version" will return 1 if you input A. If you input any other string, it actually throws an error. But, if an error were not thrown, all three if statements would be executed, and the result of the last one is actually returned.
This is closer to your C++ code:
(defn str-to-num [c]
(if ( = (str (first c )) "A") (print 1))
(if ( = (str (first c )) "J") (print 2))
(if ( = (str (first c )) "K") (print 3)))
Context
I want to generate all characters that can be generated by:
opening note pad
pressing a single key on the keyboard
holding shift + pressing a single key on the keyboard
What I currently have:
(concat (range (int \a) (int \z))
(range (int \A) (int \Z))
(range (int \0) (int \9)))
then manually appending more characters like ~!##$%^&*()_+{}|:"<>?,./;'[]\
Question
Is there a more elegant way of doing this?
Edits
Yes, I'm referring to US Qwerty keyboard.
If you look at a US ASCII chart, it seems that all the characters you want are within (range 33 127). So the simplest way to get a sequence of all those characters is to convert that range to characters.
(map char (range 33 127))
But if you are trying to validate that a string contains only those characters, have a function like:
(defn valid-char? [c]
(let [i (int c)]
(and (> i 32) (< i 127))))
Then you can use it with every? to validate a string:
user=> (every? valid-char? "hello world")
true
user=> (every? valid-char? "héllo world")
false
Using the following map form will generate the characters you want.
(map #(str (char %)) (range 32 127))
Is there an idiomatic way of encoding and decoding a string in Clojure as hexadecimal? Example from Python:
'Clojure'.encode('hex')
# ⇒ '436c6f6a757265'
'436c6f6a757265'.decode('hex')
# ⇒ 'Clojure'
To show some effort on my part:
(defn hexify [s]
(apply str
(map #(format "%02x" (int %)) s)))
(defn unhexify [hex]
(apply str
(map
(fn [[x y]] (char (Integer/parseInt (str x y) 16)))
(partition 2 hex))))
(hexify "Clojure")
;; ⇒ "436c6f6a757265"
(unhexify "436c6f6a757265")
;; ⇒ "Clojure"
Since all posted solutions have some flaws, I'm sharing my own:
(defn hexify "Convert byte sequence to hex string" [coll]
(let [hex [\0 \1 \2 \3 \4 \5 \6 \7 \8 \9 \a \b \c \d \e \f]]
(letfn [(hexify-byte [b]
(let [v (bit-and b 0xFF)]
[(hex (bit-shift-right v 4)) (hex (bit-and v 0x0F))]))]
(apply str (mapcat hexify-byte coll)))))
(defn hexify-str [s]
(hexify (.getBytes s)))
and
(defn unhexify "Convert hex string to byte sequence" [s]
(letfn [(unhexify-2 [c1 c2]
(unchecked-byte
(+ (bit-shift-left (Character/digit c1 16) 4)
(Character/digit c2 16))))]
(map #(apply unhexify-2 %) (partition 2 s))))
(defn unhexify-str [s]
(apply str (map char (unhexify s))))
Pros:
High performance
Generic byte stream <--> string conversions with specialized wrappers
Handling leading zero in hex result
Your implementation(s) don't work for non-ascii characters,
(defn hexify [s]
(apply str
(map #(format "%02x" (int %)) s)))
(defn unhexify [hex]
(apply str
(map
(fn [[x y]] (char (Integer/parseInt (str x y) 16)))
(partition 2 hex))))
(= "\u2195" (unhexify(hexify "\u2195")))
false ; should be true
To overcome this you need to serialize the bytes of the string using the required character encoding, which can be multi-byte per character.
There are a few 'issues' with this.
Remember that all numeric types are signed in the JVM.
There is no unsigned-byte.
In idiomatic java you would use the low byte of an integer and mask it like this wherever you used it.
int intValue = 0x80;
byte byteValue = (byte)(intValue & 0xff); -- use only low byte
System.out.println("int:\t" + intValue);
System.out.println("byte:\t" + byteValue);
-- output:
-- int: 128
-- byte: -128
clojure has (unchecked-byte) to effectively do the same.
For example, using UTF-8 you can do this:
(defn hexify [s]
(apply str (map #(format "%02x" %) (.getBytes s "UTF-8"))))
(defn unhexify [s]
(let [bytes (into-array Byte/TYPE
(map (fn [[x y]]
(unchecked-byte (Integer/parseInt (str x y) 16)))
(partition 2 s)))]
(String. bytes "UTF-8")))
; with the above implementation:
;=> (hexify "\u2195")
"e28695"
;=> (unhexify "e28695")
"↕"
;=> (= "\u2195" (unhexify (hexify "\u2195")))
true
Sadly the "idiom" appears to be using the Apache Commons Codec, e.g. as done in buddy:
(ns name-of-ns
(:import org.apache.commons.codec.binary.Hex))
(defn str->bytes
"Convert string to byte array."
([^String s]
(str->bytes s "UTF-8"))
([^String s, ^String encoding]
(.getBytes s encoding)))
(defn bytes->str
"Convert byte array to String."
([^bytes data]
(bytes->str data "UTF-8"))
([^bytes data, ^String encoding]
(String. data encoding)))
(defn bytes->hex
"Convert a byte array to hex encoded string."
[^bytes data]
(Hex/encodeHexString data))
(defn hex->bytes
"Convert hexadecimal encoded string to bytes array."
[^String data]
(Hex/decodeHex (.toCharArray data)))
I believe your unhexify function is as idiomatic as it can be. However, hexify can be written in a simpler way:
(defn hexify [s]
(format "%x" (new java.math.BigInteger (.getBytes s))))