I have various strings, some like \"45\", some like \"45px\". How how I convert both of these to the number 45?
This will work on 10px
or px10
(defn parse-int [s]
(Integer. (re-find #"\d+" s )))
it will parse the first continuous digit only so
user=> (parse-int "10not123")
10
user=> (parse-int "abc10def11")
10
This isn't perfect, but here's something with filter
, Character/isDigit
and Integer/parseInt
. It won't work for floating point numbers and it fails if there is no digit in the input, so you should probably clean it up. I hope there's a nicer way of doing this that doesn't involve so much Java.
user=> (defn strToInt [x] (Integer/parseInt (apply str (filter #(Character/isDigit %) x))))
#'user/strToInt
user=> (strToInt "45px")
45
user=> (strToInt "45")
45
user=> (strToInt "a")
java.lang.NumberFormatException: For input string: "" (NO_SOURCE_FILE:0)
The question asks about parsing a string into a number.
(number? 0.5)
;;=> true
So from the above decimals ought to be parsed as well.
Perhaps not exactly answering the question now, but for general use I think you would want to be strict about whether it is a number or not (so "px" not allowed) and let the caller handle non-numbers by returning nil:
(defn str->number [x]
(when-let [num (re-matches #"-?\d+\.?\d*" x)]
(try
(Float/parseFloat num)
(catch Exception _
nil))))
And if Floats are problematic for your domain instead of Float/parseFloat
put bigdec
or something else.
How about this one to avoid an exception on certain strings ?
(defn string-to-number [in]
(let [s (strip-whitespace in) ;; trim
f (re-find #"\d+" s)] ;; search digit else nil
(if f (Integer/parseInt f) 0))) ;; if not-nil do cast
(string-to-number "-")
(string-to-number "10")
(string-to-number "px10")
(string-to-number "1200 xr")
(defn parse-int [s]
(Integer. (re-find #"[0-9]*" s)))
user> (parse-int "10px")
10
user> (parse-int "10")
10
I like snrobot's answer better. Using the Java method is simpler and more robust than using read-string for this simple use case. I did make a couple of small changes. Since the author didn't rule out negative numbers, I adjusted it to allow negative numbers. I also made it so it requires the number to start at the beginning of the string.
(defn parse-int [s]
(Integer/parseInt (re-find #"\A-?\d+" s)))
Additionally I found that Integer/parseInt parses as decimal when no radix is given, even if there are leading zeroes.
First, to parse just an integer (since this is a hit on google and it's good background information):
You could use the reader:
(read-string "9") ; => 9
You could check that it's a number after it's read:
(defn str->int [str] (if (number? (read-string str))))
I'm not sure if user input can be trusted by the clojure reader so you could check before it's read as well:
(defn str->int [str] (if (re-matches (re-pattern "\\d+") str) (read-string str)))
I think I prefer the last solution.
And now, to your specific question. To parse something that starts with an integer, like 29px
:
(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29