How to compare two # character in clojure - clojure

Please, how can I write this in clojure? I have an # character and I want to compare it to "#".
eg (= # "#")
gives error (ClassCastException java.lang.String cannot be cast to java.util.concurrent.Future clojure.core/deref-future (core.clj:2206))

There's an inherent conflict in this comparison, in that "#" is a string sequence of characters and \# is an individual character. If you wanted to confirm that the string consisted of a single character which matched the \# symbol, something like the following would be work:
(let [s "#"]
(and (= \# (first s)) (= (count s) 1)))
However, if you want to detect if the string contains any \# characters or if it just started with an \# character, that requires different code. This is the problem with comparing strings and characters -- it's not inherently obvious what you need from the comparison.

Why do you get the error? The reader translates your example into ...
(= (deref "#"))
The deref function tests whether the argument is deref-able (implementing IDeref). If not, it treats the argument as a future. It isn't, so it throws the confusing exception. This behaviour is a defect, albeit a minor one.
By the way, (= x) returns true for any x, if it returns at all.
Tim Clemons' answer shows what you can do about this.

Yoy can quote your # using \# for Clojure to interpret it as a character literal. By default # is a reader macro for a deref form to make many other things in clojure less verbose. Anyway:
(= \# \#)
true
If you want to check that the first character of a string is a # then:
(= \# (first "#"))
true
The following only works in Clojurescript as it doesn't have a character type and just uses strings of length one.
(= \# "#")
true ;; in cljs only

Related

(Clojure) Count how many times any character appear in a string

I am trying to write a function (char-count) which takes a pattern and a string, then returns a number (count) which represents how many times any of the characters in the pattern appear in the string.
For example:
(char-count "Bb" "Best buy")
would return 2 since there is 1 match for B and 1 match for b, so added together we get 2
(char-count "AaR" "A Tale of Recursion")
would return 3 and so on
I tried using re-seq in my function, but it seems to work only for continuous strings. As in (re-seq #Bb "Best Buy) only looks for the pattern Bb, not for each individual character.
This is what my function looks like so far:
(defn char-count [pattern text]
(count (re-seq (#(pattern)) text)))
But it does not do what I want. Can anybody help?
P.s. Very new to clojure (and functional programming in general).
You don't need anything nearly as powerful as a regular expression here, so just use the simple tools your programming language comes with: sets and functions. Build a set of the characters you want to find, and count how many characters from the input string are in the set.
(defn char-count [chars s]
(count (filter (set chars) s)))
Try wrapping the characters in [...] within the RegEx:
(count (re-seq #"[Bb]" "Best buy"))
Or, since you need that pattern to be dynamic:
(count (re-seq (re-pattern (str "[" pattern "]")) text))
But note that the solution might not work properly if the pattern contains special RegEx characters such as [, ], \, -, ^ - you'd have to escape them by prepending \\ in front of each one.

Mapping a string using a map

(def conversions {"G" "C"
"C" "G"
"T" "A"
"A" "U"})
(defn to-rna [dna]
(map conversions dna)
)
(conversions "G") ;; Gives "C"
(to-rna "GC") ;; Gives (nil nil)
I'm attempting to do an exercise where I convert letters. I have a working solution, but I don't like it. I feel like the above ought to work, but evidently I'm wrong, because it doesn't.
Could someone explain to me why this is, and how I might properly achieve this?
When mapping over a string, it will treat the string as a sequence of characters. So, your code ends up looking for a \G and a \C entry in the map, which both return nil.
As dpassen says, you need to put a java.lang.Character in the map, not a length-1 string. Try this:
(def conversions { \G \C
\C \G
\T \A
\A \U })
I'm just starting learning Clojure myself so please take this answer with caution.
In addition to what's been already suggested, I would put the conversions map into a let form to keep your function "isolated". (As is, your function relies on a conversions being defined outside of its scope).
I also read (can't remember where exactly) that a common naming convention when writing functions that "convert" X to Y should be named as follow: x->y.
Finally I'd use a threading macro for improved readability.
(defn dna->rna [dna]
(let [conversions {\G \C
\C \G
\T \A
\A \U}]
(->> dna
(map conversions)
(string/join ""))))
(dna->rna "GC")
;; "CG"
FYI, Clojure has clojure.string/escape and clojure.string/replace that you might want to look at. escape is probably most similar to what you are doing.

How to correctly check if a string is equal to another string in Clojure?

I am looking for better ways to check if two strings are equal in Clojure!
Given a map 'report' like
{:Result Pass}
, when I evaluate
(type (:Result report))
I get : Java.Lang.String
To write a check for the value of :Result, I first tried
(if (= (:Result report) "Pass") (println "Pass"))
But the check fails.
So I used the compare method, which worked:
(if (= 0 (compare (:Result report) "Pass")) (println "Pass"))
However, I was wondering if there is anything equivalent to Java's .equals() method in Clojure. Or a better way to do the same.
= is the correct way to do an equality check for Strings. If it's giving you unexpected results, you likely have whitespace in the String like a trailing newline.
You can easily check for whitespace by using vec:
(vec " Pass\n")
user=> [\space \P \a \s \s \newline]
As #Carcigenicate wrote, use = to compare strings.
(= "hello" "hello")
;; => true
If you want to be less strict, consider normalizing your string before you compare. If we have a leading space, the strings aren't equal.
(= " hello" "hello")
;; => false
We can then define a normalize function that works for us.
In this case, ignore leading and trailing whitespace and
capitalization.
(require '[clojure.string :as string])
(defn normalize [s]
(string/trim
(string/lower-case s)))
(= (normalize " hellO")
(normalize "Hello\t"))
;; => true
Hope that helps!

Escaping brackets in Clojure

If I try this
(import java.util.regex.Pattern)
(Pattern/compile ")!##$%^&*()")
or this
(def p #")!##$%^&*()")
I have Clojure complaining that there is an unmatched / unclosed ). Why are brackets evaluated within this simple string? How to escape them? Thanks
EDIT: While escaping works in the clojure-specific syntax (#""), it doesn't work with the Pattern/compile syntax that I do need because I have to compile the regex patter dynamically from a string.
I've tried with re-pattern, but I can't escape properly for some reason:
(re-pattern "\)!##$%^&*\(\)")
java.lang.Exception: Unsupported escape character: \)
java.lang.Exception: Unable to resolve symbol: ! in this context (NO_SOURCE_FILE:0)
java.lang.Exception: No dispatch macro for: $
java.lang.Exception: Unable to resolve symbol: % in this context (NO_SOURCE_FILE:0)
java.lang.IllegalArgumentException: Metadata can only be applied to IMetas
EDIT 2 This little function may help:
(defn escape-all [x]
(str "\\" (reduce #(str %1 "\\" %2) x)))
I got it working by double escaping everything. Oh the joys of double escaping.
=> (re-pattern "\\)\\!\\#\\#\\$\\%\\^\\&\\*\\(\\)")
=> #"\)\!\#\#\$\%\^\&\*\(\)"
=> (re-find (re-pattern "\\)\\!\\#\\#\\$\\%\\^\\&\\*\\(\\)")
")!##$%^&*()")
=> ")!##$%^&*()"
I would recommend writing a helper function str-to-pattern (or whatever you want to call it), that takes a string, double escapes everything it needs to, and then calls re-pattern on it.
Edit: making a string to pattern function
There are plenty of ways to do this, below is just one example. I start by making an smap of regex escape chars to their string replacement. An "smap" isn't an actual type, but functionally it's a map we will use to swap "old values" with "new values", where "old values" are members of the keys of the smap, and "new values" are corresponding members of the vals of smap. In our case, this smap looks like {\( "\\(", \) "\\)" ...}.
(def regex-char-esc-smap
(let [esc-chars "()*&^%$#!"]
(zipmap esc-chars
(map #(str "\\" %) esc-chars))))
Next is the actual function. I use the above smap to replace items in the string passed to it, then convert that back into a string and make a regex pattern out of it. I think the ->> macro makes the code more readable, but that's just a personal preference.
(defn str-to-pattern
[string]
(->> string
(replace regex-char-esc-smap)
(reduce str)
re-pattern))
are you sure the error is from the reader (ie from clojure itself)?
regexps use parentheses, and they have to match there too. i would guess the error is cominng from the code trying to compile the regexp.
if you want to escape a paren in a regexp, use a backquote: (def p #"\)!##$%^&*\(\)")
[update] ah, sorry, you probably need double escapes as Omri days.
All of the versions of Java that Clojure supports recognize \Q to start a quoted region and \E to end the quoted region. This allows you to do something like this:
(re-find #"\Q)!##$%^&*()\E" ")!##$%^&*()")
If you're using (re-pattern) then this will work:
(re-find (re-pattern "\\Q)!##$%^&*()\\E") ")!##$%^&*()")
If you're assembling a regular expression from a string whose content you don't know then you can use the quote method in java.util.regex.Pattern:
(re-find (re-pattern (java.util.regex.Pattern/quote some-str)) some-other-str)
Here's an example of this from my REPL:
user> (def the-string ")!##$%^&*()")
#'user/the-string
user> (re-find (re-pattern (java.util.regex.Pattern/quote the-string)) the-string)
")!##$%^&*()"

regexp for elisp

In Emacs I would like to write some regexp that does the following:
First, return a list of all dictionary words that can be formed within "hex space". By this I mean:
#000000 - #ffffff
so #00baba would be a word (that can be looked up in the dictionary)
so would #baba00
and #abba00
and #0faded
...where trailing and leading 0's are considered irrelevant. How would I write this? Is my question clear enough?
Second, I would like to generate a list of words that can be made using numbers as letters:
0 = o
1 = i
3 = e
4 = a
...and so on. How would I write this?
First, load your dictionary. I'll assume that you're using /var/share/dict/words, which is nearly always installed by default when you're running Linux. It lists one word per line, which is a very handy format for this sort of thing.
Next run M-x keep-lines. It'll ask you for a regular expression and then delete any line that doesn't match it. Use the regex ^[a-f]\{,6\}$ and it will filter out anything that can't be part of a color.
Specifically, the ^ makes the regex start at the beginning of the line, the [a-f] matches any one character that is between a and f (inclusive), the {,6} lets it match between 0 and 6 instances of the previous item (in this case the character class [a-f] and finally the $ tells it that the next thing must be the end of the line.
This will return a list of all instances of #000000 - #ffffff in the buffer, although this pattern may not be restrictive enough for your purposes.
(let ((my-colour-list nil))
(save-excursion
(goto-char (point-min))
(while (re-search-forward "#[0-9a-fA-F]\\{6\\}" nil t)
(add-to-list 'my-colour-list (match-string-no-properties 0)))
my-colour-list))
I'm not actually certain that this is what you were asking for. What do you mean by "dictionary"?
A form that will return you a hash table with all the elements you specify in it could be this:
(let ((hash-table (make-hash-table :test 'equal)))
(dotimes (i (exp 256 3))
(puthash (concat "#" (format "%06x" i)) t hash-table))
hash-table)
I'm not sure how Emacs will manage that size of elements (16 million). As you don't want the 0, you can generate the space without that format, and removing trailing 0's. I don't know what do you want to do with the rest of the numbers. You can write the function step by step like this then:
(defun find-hex-space ()
(let (return-list)
(dotimes (i (exp 256 3))
(let* ((hex-number (strip-zeros (format "%x" i)))
(found-word (gethash hex-number *dictionary*)))
(if found-word (push found-word return-list))))
return-list))
Function strip-zeros is easy to write, and here I suppose your words are in a hash called *dictionary*. strip-zeros could be something like this:
(defun strip-zeros (string)
(let ((sm (string-match "^0*\\(.*?\\)0*$" string)))
(if sm (match-string 1 string) string)))
I don't quite understand your second question. The words would be also using the hex space? Would you then consider only the words formed by numbers, or would also include the letters in the word?