I have various strings, some like "45", some like "45px". How how I convert both of these to the number 45?
-
45I am glad someone is not afraid to ask some basic questions. – octopusgrabbus Oct 13 '11 at 21:50
-
4+1 - part of the challenge is that the Clojure docs sometimes don't address these "basic" questions that we take for granted in other languages. (I had the same question 3 years later and found this). – Glenn Jun 18 '14 at 12:03
-
3@octopusgrabbus - I would be interested to know "why" people are afraid of asking basic questions? – yazz.com Jan 26 '15 at 09:29
-
1@Zubair it is supposed basic things are explained somewhere already so you most probably overlooked something and your question will be downvoted for "no research effort". – Al.G. Oct 12 '18 at 19:09
-
@Al.G. Yes, I think you are right. I did research this and couldn't find the answer anywhere at the time. If you could send me a link to where it was explained then that would be much appreciated – yazz.com Oct 14 '18 at 04:40
-
2For those coming here from Google looking to convert `"9"` into `9`, this is the best thing that worked for me: `(Integer. "9")`. – Dennis Hackethal Nov 11 '19 at 00:15
13 Answers
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

- 2,438
- 1
- 18
- 9
-
Nice answer! This is better than using read-string in my opinion. I changed my answer to use your technique. I made a couple of small changes as well. – Benjamin Atkin Oct 09 '13 at 05:47
-
2this gives me `Exception in thread "main" java.lang.ClassNotFoundException: Integer., ` – maazza Mar 31 '20 at 08:15
New answer
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.
Old answer
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

- 1
- 1

- 14,071
- 7
- 61
- 60
-
I like your answer best - too bad this isn't provided by the clojure core library. One minor critique - technically your `if` should be a `when` since there is no else block in your fns. – quux00 Dec 26 '12 at 02:28
-
1Yeah, please don't stop reading after the first or second code snippet! – Benjamin Atkin Mar 22 '13 at 04:00
-
2A heads-up on numbers with leading zeros. `read-string` interprets them as octal: `(read-string "08")` throws an exception. `Integer/valueOf` treats them as decimal: `(Integer/valueOf "08")` evaluates to 8. – rubasov Apr 05 '13 at 15:06
-
Note also that `read-string` throws an exception if you give it an empty string or something like "29px" – Ilya Boyandin May 02 '13 at 12:56
-
As it should. I answered the question in the title, and what people expect when they see this page, before I answered the question in the question body. It's the last code snippet in the body of my answer. – Benjamin Atkin May 31 '13 at 19:16
-
-
For my requirement of converting string of integer or flotating number to number, I like read-string better. – Yu Shen Oct 27 '20 at 22:19
(defn parse-int [s]
(Integer. (re-find #"[0-9]*" s)))
user> (parse-int "10px")
10
user> (parse-int "10")
10

- 1,484
- 1
- 11
- 12
-
Thanks. This was helpful in my splitting a product up into a sequence of digits. – octopusgrabbus Oct 13 '11 at 21:50
-
3Since we are in Java land for this answer, it is generally advisable to use `Integer/valueOf`, rather than the Integer constructor. The Integer class caches values between -128 and 127 to minimize object creation. The Integer Javadoc describes this as does this post: http://stackoverflow.com/a/2974852/871012 – quux00 Nov 25 '12 at 20:42
This works in repl for me, much more straight forward.
(read-string "123")
=> 123

- 191
- 1
- 5
-
4Be careful using this with user input. `read-string` can execute code per the docs: https://clojuredocs.org/clojure.core/read-string – jerney Mar 09 '19 at 20:03
-
this is great for trusted input, like e.g. a programming puzzle. @jerney is right: be careful not to use it in actual code. – hraban Mar 17 '19 at 15:05
AFAIK there's no standard solution for your problem. I think something like the following, which uses clojure.contrib.str-utils2/replace
, should help:
(defn str2int [txt]
(Integer/parseInt (replace txt #"[a-zA-Z]" "")))

- 13,414
- 1
- 48
- 67
-
1Not recommended. It will work until somebody throws `1.5` at it...and it also doesn't make use of the built-in `clojure.string/replace` function. – tar Jan 04 '17 at 18:20
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)

- 8,355
- 39
- 51
For anyone else looking to parse a more normal String literal into a number, that is, a string which doesn't have other non numeric characters. These are the two best approaches:
Using Java interop:
(Long/parseLong "333")
(Float/parseFloat "333.33")
(Double/parseDouble "333.3333333333332")
(Integer/parseInt "-333")
(Integer/parseUnsignedInt "333")
(BigInteger. "3333333333333333333333333332")
(BigDecimal. "3.3333333333333333333333333332")
(Short/parseShort "400")
(Byte/parseByte "120")
This lets you precisely control the type you want to parse the number in, when that matters to your use case.
Using the Clojure EDN reader:
(require '[clojure.edn :as edn])
(edn/read-string "333")
Unlike using read-string
from clojure.core
which isn't safe to use on untrusted input, edn/read-string
is safe to run on untrusted input such as user input.
This is often more convenient then the Java interop if you don't need to have specific control of the types. It can parse any number literal that Clojure can parse such as:
;; Ratios
(edn/read-string "22/7")
;; Hexadecimal
(edn/read-string "0xff")
Full list here: https://www.rubberducking.com/2019/05/clojure-for-non-clojure-programmers.html#numbers

- 4,609
- 2
- 43
- 45
Expanding on snrobot's answer:
(defn string->integer [s]
(when-let [d (re-find #"-?\d+" s)] (Integer. d)))
This versions returns nil if there are no digits in the input, rather than raising an exception.
My question is whether it's acceptable to abbreviate the name to "str->int", or if things like this should always be fully specified.

- 51
- 2
- 4
I would probably add a few things to the requirements:
- Has to start with a digit
- Has to tolerate empty inputs
- Tolerates being passed any object (toString is standard)
Maybe something like:
(defn parse-int [v]
(try
(Integer/parseInt (re-find #"^\d+" (.toString v)))
(catch NumberFormatException e 0)))
(parse-int "lkjhasd")
; => 0
(parse-int (java.awt.Color. 4 5 6))
; => 0
(parse-int "a5v")
; => 0
(parse-int "50px")
; => 50
and then perhaps bonus points for making this a multi-method that allows for a user-supplied default other than 0.

- 5,535
- 23
- 27
Also using (re-seq)
function can extend the return value to a string containing all the numbers existing in the input string in order:
(defn convert-to-int [s]
(->> (re-seq #"\d" s)
(apply str)
(Integer.)))
(convert-to-int "10not123")
=> 10123
(type *1)
=> java.lang.Integer
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.

- 6,411
- 1
- 24
- 42
For simple cases you can just use a regex to pull out the first string of digits as mentioned above.
If you have a more complicated situation you may wish to use the InstaParse library:
(ns tst.parse.demo
(:use tupelo.test)
(:require
[clojure.string :as str]
[instaparse.core :as insta]
[tupelo.core :as t] ))
(t/refer-tupelo)
(dotest
(let [abnf-src "
size-val = int / int-px
int = digits ; ex '123'
int-px = digits <'px'> ; ex '123px'
<digits> = 1*digit ; 1 or more digits
<digit> = %x30-39 ; 0-9
"
tx-map {:int (fn fn-int [& args]
[:int (Integer/parseInt (str/join args))])
:int-px (fn fn-int-px [& args]
[:int-px (Integer/parseInt (str/join args))])
:size-val identity
}
parser (insta/parser abnf-src :input-format :abnf)
instaparse-failure? (fn [arg] (= (class arg) instaparse.gll.Failure))
parse-and-transform (fn [text]
(let [result (insta/transform tx-map
(parser text))]
(if (instaparse-failure? result)
(throw (IllegalArgumentException. (str result)))
result))) ]
(is= [:int 123] (parse-and-transform "123"))
(is= [:int-px 123] (parse-and-transform "123px"))
(throws? (parse-and-transform "123xyz"))))

- 29,276
- 6
- 41
- 48
-
Also, just a curious question: why do you use `(t/refer-tupelo)` instead of getting the user to do `(:require [tupelo.core :refer :all])`? – Qwerp-Derp Oct 24 '17 at 05:01
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")

- 21
- 2