Не уверен, что это "самый простой способ", но я подумал, что это довольно забавно, так что ... С помощью взлома отражения вы можете получить доступ только к части чтения чисел в Clojure Reader:
(let [m (.getDeclaredMethod clojure.lang.LispReader
"matchNumber"
(into-array [String]))]
(.setAccessible m true)
(defn parse-number [s]
(.invoke m clojure.lang.LispReader (into-array [s]))))
Тогда используйте так:
user> (parse-number "123")
123
user> (parse-number "123.5")
123.5
user> (parse-number "123/2")
123/2
user> (class (parse-number "123"))
java.lang.Integer
user> (class (parse-number "123.5"))
java.lang.Double
user> (class (parse-number "123/2"))
clojure.lang.Ratio
user> (class (parse-number "123123451451245"))
java.lang.Long
user> (class (parse-number "123123451451245123514236146"))
java.math.BigInteger
user> (parse-number "0x12312345145124")
5120577133367588
user> (parse-number "12312345142as36146") ; note the "as" in the middle
nil
Обратите внимание, как это не выбрасывает обычный NumberFormatException
, если что-то идет не так; Вы можете добавить чек на nil
и бросить его самостоятельно, если хотите.
Что касается производительности, давайте создадим ненаучный микробенчмарк (обе функции были "прогреты"; начальные прогоны были, как обычно, медленнее):
user> (time (dotimes [_ 10000] (parse-number "1234123512435")))
"Elapsed time: 564.58196 msecs"
nil
user> (time (dotimes [_ 10000] (read-string "1234123512435")))
"Elapsed time: 561.425967 msecs"
nil
Очевидный отказ от ответственности: clojure.lang.LispReader.matchNumber
является частным статическим методом clojure.lang.LispReader
и может быть изменен или удален в любое время.