Я использовал Java для парсинга чисел, например.
(. Integer parseInt numberString)
Существует ли больше clojuriffic пути, который обработал бы и целые числа и плавания, и возвратил бы clojure числа? Я особенно не волнуюсь по поводу производительности здесь, я просто хочу обработать набор разграниченных чисел пробела в файле и сделай что-то с ними самым простым возможным способом.
Таким образом, файл мог бы иметь строки как:
5 10 0.0002
4 12 0.003
И я хотел бы смочь преобразовать строки в векторы чисел.
Для анализа чисел можно использовать программу чтения edn . Это дает вам то преимущество, что при необходимости вы получаете поплавки или Bignum.
user> (require '[clojure.edn :as edn])
nil
user> (edn/read-string "0.002")
0.0020
Если вам нужен один огромный вектор чисел, вы можете схитрить и сделать следующее:
user> (let [input "5 10 0.002\n4 12 0.003"]
(read-string (str "[" input "]")))
[5 10 0.0020 4 12 0.0030]
Хотя это вроде хакерство. Или есть re-seq
:
user> (let [input "5 10 0.002\n4 12 0.003"]
(map read-string (re-seq #"[\d.]+" input)))
(5 10 0.0020 4 12 0.0030)
Или один вектор на строку:
user> (let [input "5 10 0.002\n4 12 0.003"]
(for [line (line-seq (java.io.BufferedReader.
(java.io.StringReader. input)))]
(vec (map read-string (re-seq #"[\d.]+" line)))))
([5 10 0.0020] [4 12 0.0030])
Я уверен, что есть другие способы.
Не уверен, что это «самый простой способ», но я подумал, что это было весело, так что ... С помощью хака отражения вы можете получить доступ только к части чтения чисел Clojure's 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
и может быть изменен или удален в любое время.
Если вы хотите быть в большей безопасности, вы можете использовать Float / parseFloat
user=> (map #(Float/parseFloat (% 0)) (re-seq #"\d+(\.\d+)?" "1 2.2 3.5"))
(1.0 2.2 3.5)
user=>