我有不同的字符串,像“45”和“45px”。如何将这两个字符串转换为数字45?
这将适用于 10px
或 px10
(defn parse-int [s]
(Integer. (re-find #"\d+" s )))
它将仅解析第一个连续数字,所以
user=> (parse-int "10not123")
10
user=> (parse-int "abc10def11")
10
Exception in thread "main" java.lang.ClassNotFoundException: Integer.
- maazza我更喜欢snrobot的答案。对于这个简单的用例来说,使用Java方法比使用read-string更简单和更健壮。我进行了一些小修改。由于作者没有排除负数,所以我将其调整为允许负数。我还使它要求数字从字符串开头开始。
(defn parse-int [s]
(Integer/parseInt (re-find #"\A-?\d+" s)))
此外我发现,当没有给出基数时,Integer / parseInt解析为十进制,即使存在前导零。
首先,为了解析整数(因为这是谷歌搜索的结果并且是良好的背景信息):
您可以使用读取器:
(read-string "9") ; => 9
在读取后,您可以检查它是否为数字:
(defn str->int [str] (if (number? (read-string str))))
我不确定Clojure reader是否能够信任用户输入,因此您可以在读取之前进行检查:
(defn str->int [str] (if (re-matches (re-pattern "\\d+") str) (read-string str)))
我认为我更喜欢最后的解决方案。
现在,回到你的具体问题。要解析以整数开头的内容,比如 29px
:
(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
if
应该是一个when
,因为在你的fns中没有else块。 - quux00read-string
会将它们解释为八进制:(read-string "08")
会抛出异常。而Integer/valueOf
则将其视为十进制:(Integer/valueOf "08")
的结果为8。 - rubasovread-string
提供空字符串或类似于“29px”的内容,则会引发异常。 - Ilya Boyandin(defn parse-int [s]
(Integer. (re-find #"[0-9]*" s)))
user> (parse-int "10px")
10
user> (parse-int "10")
10
Integer/valueOf
而非Integer构造函数。Integer类会缓存-128到127之间的值,以最小化对象创建。Integer Javadoc和此文章(链接为https://dev59.com/jHA85IYBdhLWcg3wBO7h#2974852)都有描述这一点。 - quux00对我来说,在repl中这很有效,更加简单。
(read-string "123")
=> 123
read-string
函数可以执行代码。详情请见:https://clojuredocs.org/clojure.core/read-string - jerney据我所知,针对您的问题并没有标准解决方案。我认为以下代码可以帮助解决,它使用了clojure.contrib.str-utils2/replace
:
(defn str2int [txt]
(Integer/parseInt (replace txt #"[a-zA-Z]" "")))
1.5
传递进来...而且它也没有使用内置的 clojure.string/replace
函数。 - tar这并不完美,但是下面的方法利用了filter
, Character/isDigit
和Integer/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)
如果其他人想将一个更普通的字符串字面值解析为数字,即一个不包含其他非数值字符的字符串。以下是两种最好的方法:
使用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")
(require '[clojure.edn :as edn])
(edn/read-string "333")
;; Ratios
(edn/read-string "22/7")
;; Hexadecimal
(edn/read-string "0xff")
完整列表请查看这里:https://www.rubberducking.com/2019/05/clojure-for-non-clojure-programmers.html#numbers
对snrobot的回答进行进一步扩展:
(defn string->integer [s]
(when-let [d (re-find #"-?\d+" s)] (Integer. d)))
此版本如果输入中没有数字,则返回nil,而不是引发异常。
我的问题是是否可以将名称缩写为“str->int”,或者像这样的东西应该始终完全指定。
我认为需要增加一些要求:
也许可以像这样实现:
(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
另外,如果您能将其变成一种多方法,允许用户提供默认值而不是0,那就更好了。
同时使用 (re-seq)
函数可以将返回值扩展为按顺序包含输入字符串中所有数字的字符串:
(defn convert-to-int [s]
(->> (re-seq #"\d" s)
(apply str)
(Integer.)))
(convert-to-int "10not123")
=> 10123
(type *1)
=> java.lang.Integer
"9"
转换为9
的人,这是我使用过最好的方法:(Integer. "9")
。 - Dennis Hackethal