首页 > 解决方案 > 在 ClojureScript 程序中使用 Cuerdas 解析十进制数

问题描述

我在 ClojureScript 程序中使用Cuerdas 库来解析浮点数。有时来自用户的输入缺少不可或缺的部分,例如.1for 0.1。我需要处理这个。但是在比较解析的数字时,我遇到了奇怪的结果:

(= 0.1 (parse-number "0.1"))
;; => true

(= .1 (parse-number "0.1"))
;; => true

(= 0.1 (parse-number ".1"))
;; => false

(= .1 (parse-number ".1"))
;; => false

上面的最后两个结果让我感到惊讶。比较文字数字时,我得到了预期的结果:

(= 0 .0)
;; => true

当我只解析没有整数部分的十进制数时,也可以看到奇怪的行为,如下所示:

(parse-number ".1")
;; => .1

.1
;; => 0.1

我发现我可以用它js/parseFloat来获得我想要的东西,但我很好奇在使用 Cuerdas 时这种行为的原因是什么?这个.1值是多少,它与 有何不同0.1

标签: parsingfloating-pointnumbersdecimalclojurescript

解决方案


parse-number源看起来像这样:

(defn parse-number
  "General purpose function for parse number like
  string to number. It works with both integers
  and floats."
  [s]
  (if (nil? s)
    #?(:cljs js/NaN :clj Double/NaN)
    (if (numeric? s)
      (edn/read-string s)
      #?(:cljs js/NaN :clj Double/NaN))))

两者".1""0.1"都被认为是numeric?(通过正则表达式检查在 cuerdas 中实现):

cljs.user=> (def re #"^[+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)([eE][+-]?[0-9]+)?$")
#'cljs.user/re
cljs.user=> (boolean (re-matches re "0.1"))
true
cljs.user=> (boolean (re-matches re ".1"))
true

所以他们会被cljs.reader/read-string.

读取字符串时"0.1",返回类型为 a js/Number,但".1"类型为cljs.core/Symbol

cljs.user=> (cljs.reader/read-string ".1")
.1
cljs.user=> (cljs.reader/read-string "0.1")
0.1
cljs.user=> (type (cljs.reader/read-string "0.1"))
#object[Number]
cljs.user=> (type (cljs.reader/read-string ".1"))
cljs.core/Symbol

因此,尽管看起来它正确地解析了 .1,但它实际上将它变成了一个符号。符号.1不等于数字.1

请注意,在较新版本的 cuerdasparse-number不再可用,因为它“是一个字符串操作库而不是数字解析库”。


推荐阅读