在Clojure中,如何将String转换为数字?

Zub*_*air 121 clojure

我有各种各样的字符串,有些像"45",有些像"45px".我如何将这两个转换为45?

Ben*_*kin 79

新答案

我更喜欢snrobot的答案.对于这个简单的用例,使用Java方法比使用read-string更简单,更健壮.我确实做了一些小改动.由于作者没有排除负数,我调整它以允许负数.我也这样做了它需要数字从字符串的开头开始.

(defn parse-int [s]
  (Integer/parseInt (re-find #"\A-?\d+" s)))
Run Code Online (Sandbox Code Playgroud)

另外,我发现Integer/parseInt在没有给出基数的情况下解析为十进制,即使有前导零也是如此.

老答案

首先,解析一个整数(因为这是谷歌的一个命中,它是很好的背景信息):

你可以使用读者:

(read-string "9") ; => 9
Run Code Online (Sandbox Code Playgroud)

您可以在阅读后检查它是否为数字:

(defn str->int [str] (if (number? (read-string str))))
Run Code Online (Sandbox Code Playgroud)

我不确定clojure读者是否可以信任用户输入,因此您可以在读取之前进行检查:

(defn str->int [str] (if (re-matches (re-pattern "\\d+") str) (read-string str)))
Run Code Online (Sandbox Code Playgroud)

我想我更喜欢最后的解决方案.

现在,针对您的具体问题.要解析以整数开头的内容,例如29px:

(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
Run Code Online (Sandbox Code Playgroud)

  • 带有前导零的数字单挑.`read-string`将它们解释为八进制:`(read-string"08")`抛出异常.`Integer/valueOf`将它们视为十进制:`(Integer/valueOf"08")`计算结果为8. (2认同)

小智 77

这将适用于10pxpx10

(defn parse-int [s]
   (Integer. (re-find  #"\d+" s )))
Run Code Online (Sandbox Code Playgroud)

它只解析第一个连续数字

user=> (parse-int "10not123")
10
user=> (parse-int "abc10def11")
10
Run Code Online (Sandbox Code Playgroud)

  • 这给了我`线程“main”java.lang.ClassNotFoundException中的异常:Integer。,` (2认同)

May*_*iel 29

(defn parse-int [s]
  (Integer. (re-find #"[0-9]*" s)))

user> (parse-int "10px")
10
user> (parse-int "10")
10
Run Code Online (Sandbox Code Playgroud)

  • 由于我们在Java中找到了这个答案,因此通常建议使用`Integer/valueOf`,而不是Integer构造函数.Integer类将值缓存在-128和127之间,以最大限度地减少对象创建.Integer Javadoc就像这篇文章一样描述了这个:http://stackoverflow.com/a/2974852/871012 (3认同)

小智 16

这对我来说很复杂,更直截了当.

(读取字符串"123")

=> 123

  • 在用户输入中使用它时要小心。`read-string` 可以按照文档执行代码:https://clojuredocs.org/clojure.core/read-string (2认同)

sku*_*uro 9

AFAIK没有针对您的问题的标准解决方案.我认为以下类似的东西clojure.contrib.str-utils2/replace应该有所帮助:

(defn str2int [txt]
  (Integer/parseInt (replace txt #"[a-zA-Z]" "")))
Run Code Online (Sandbox Code Playgroud)


mic*_*kig 7

这不是完美的,但这里有一些东西filter,Character/isDigitInteger/parseInt.它对浮点数不起作用,如果输入中没有数字则失败,所以你应该清理它.我希望有一个更好的方法来做到这一点,不涉及这么多的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)
Run Code Online (Sandbox Code Playgroud)


Did*_* A. 6

对于任何其他希望将更普通的字符串文字解析为数字(即不包含其他非数字字符的字符串)的人。这是两种最好的方法:

使用 Java 互操作:

(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")
Run Code Online (Sandbox Code Playgroud)

当这对您的用例很重要时,这可以让您精确控制要解析数字的类型。

使用 Clojure EDN 阅读器:

(require '[clojure.edn :as edn])
(edn/read-string "333")
Run Code Online (Sandbox Code Playgroud)

与 using read-stringfrom不同clojure.core,using from 在不受信任的输入上使用是不安全的,而edn/read-string在不受信任的输入(例如用户输入)上运行是安全的。

如果您不需要对类型进行特定控制,这通常比 Java 互操作更方便。它可以解析 Clojure 可以解析的任何数字文字,例如:

;; Ratios
(edn/read-string "22/7")
;; Hexadecimal
(edn/read-string "0xff")
Run Code Online (Sandbox Code Playgroud)

完整列表: https: //www.rubberducking.com/2019/05/clojure-for-non-clojure-programmers.html#numbers


Nic*_*ish 5

扩展 snrobot 的答案:

(defn string->integer [s] 
  (when-let [d (re-find #"-?\d+" s)] (Integer. d)))
Run Code Online (Sandbox Code Playgroud)

如果输入中没有数字,此版本将返回 nil,而不是引发异常。

我的问题是是否可以将名称缩写为“str->int”,或者是否应该始终完全指定这样的内容。