我有各种各样的字符串,有些像“45”,有些像“45px”。怎么把这两个转换成数字45?
这不是完美的,但这里有一些与 filter,Character/isDigit和 Integer/parseInt。对于浮点数不起作用,如果输入中没有数字,它就会失败,所以您可能应该清除它。我希望有一个更好的方法来做到这一点,而不是涉及太多的 Java。
filter
Character/isDigit
Integer/parseInt
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)
AFAIK 对于你的问题没有标准的解决方案。我认为下面这些使用 clojure.contrib.str-utils2/replace的东西会有所帮助:
clojure.contrib.str-utils2/replace
(defn str2int [txt] (Integer/parseInt (replace txt #"[a-zA-Z]" "")))
(defn parse-int [s] (Integer. (re-find #"[0-9]*" s))) user> (parse-int "10px") 10 user> (parse-int "10") 10
我更喜欢 Snbot 的回答。对于这个简单的用例,使用 Java 方法比使用 read-string 更简单,也更健壮。我确实做了一些小改动。因为作者没有排除负数,所以我把它调整为允许出现负数。我还让它要求数字从字符串的开头开始。
(defn parse-int [s] (Integer/parseInt (re-find #"\A-?\d+" s)))
另外,我发现当没有给出基数时,Integer/parseInt 解析为小数,即使有前导零也是如此。
首先,解析一个整数(因为这是 google 上的热门话题,而且它是很好的背景信息) :
你可以使用 读者:
(read-string "9") ; => 9
你可以看看是不是一个数字:
(defn str->int [str] (if (number? (read-string str))))
我不确定 clojure 阅读器是否可以信任用户输入,这样你就可以在读取之前检查:
(defn str->int [str] (if (re-matches (re-pattern "\\d+") str) (read-string str)))
我想我更喜欢最后一种解决方案。
现在,回到你的具体问题,解析以整数开头的东西,比如 29px:
29px
(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
这将工作在 10px或 px10
10px
px10
(defn parse-int [s] (Integer. (re-find #"\d+" s )))
它只会解析第一个连续数字
user=> (parse-int "10not123") 10 user=> (parse-int "abc10def11") 10
我可能会在需求中添加一些内容:
比如说:
(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的额外加分。
继续补充 snRobot 的回答:
(defn string->integer [s] (when-let [d (re-find #"-?\d+" s)] (Integer. d)))
如果输入中没有数字,则此版本返回 nil,而不是引发异常。
我的问题是,是否可以将名称缩写为“ str-> int”,或者是否应该总是完全指定这样的内容。
还可以使用 (re-seq)函数将返回值扩展为包含输入字符串中存在的所有数字的字符串,其顺序如下:
(re-seq)
(defn turn-to-int [ s ] (- > (重新编号“ d”) (应用 str) (整数))
(convert-to-int "10not123") = > 10123
(convert-to-int "10not123")
10123
(type *1) = > java.lang.Integer
(type *1)
java.lang.Integer
这对我来说很有效,直截了当得多。
(read-string“123”)
= > 123
对于简单的情况,您可以只使用正则表达式拉出数字的第一个字符串,如上所述。
如果遇到更复杂的情况,可以使用 InstaParse 库:
(ns tst.parse.demo (:use tupelo.test) (:require [clojure.string :as str] [instaparse.core :as insta] [tupelo.core :as t] )) (t/refer-tupelo) (dotest (let [abnf-src " size-val = int / int-px int = digits ; ex '123' int-px = digits <'px'> ; ex '123px' <digits> = 1*digit ; 1 or more digits <digit> = %x30-39 ; 0-9 " tx-map {:int (fn fn-int [& args] [:int (Integer/parseInt (str/join args))]) :int-px (fn fn-int-px [& args] [:int-px (Integer/parseInt (str/join args))]) :size-val identity } parser (insta/parser abnf-src :input-format :abnf) instaparse-failure? (fn [arg] (= (class arg) instaparse.gll.Failure)) parse-and-transform (fn [text] (let [result (insta/transform tx-map (parser text))] (if (instaparse-failure? result) (throw (IllegalArgumentException. (str result))) result))) ] (is= [:int 123] (parse-and-transform "123")) (is= [:int-px 123] (parse-and-transform "123px")) (throws? (parse-and-transform "123xyz"))))
该问题询问如何将字符串解析为数字。
(number? 0.5) ;;=> true
因此,也应该对上述小数进行解析。
也许现在还不能完全回答这个问题,但是作为一般用途,我认为你应该严格要求它是否是一个数字(所以“ px”是不允许的) ,并且让来电者通过返回零来处理非数字:
(defn str->number [x] (when-let [num (re-matches #"-?\d+\.?\d*" x)] (try (Float/parseFloat num) (catch Exception _ nil))))
如果 Floats 对于您的域而不是 Float/parseFloat是有问题的,那么放入 bigdec或其他内容。
Float/parseFloat
bigdec
对于其他任何想要将一个更普通的字符串文字解析为数字的人,也就是说,一个没有其他非数字字符的字符串。这是两种最好的方法:
使用 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")
这使您可以精确地控制您想要解析数字的类型,当这与您的用例有关时。
使用 Clojure EDN 阅读器:
(require '[clojure.edn :as edn]) (edn/read-string "333")
与使用来自 clojure.core的 read-string不同,edn/read-string在不受信任的输入上使用是不安全的,edn/read-string在不受信任的输入(如用户输入)上运行是安全的。
clojure.core
read-string
edn/read-string
如果不需要对类型进行特定的控制,这通常比 Java 互操作更方便。它可以解析 Clojure 可以解析的任何数字字面值,比如:
;; Ratios (edn/read-string "22/7") ;; Hexadecimal (edn/read-string "0xff")
完整列表在这里: https://www.rubberducking.com/2019/05/clojure-for-non-clojure-programmers.html#numbers
为了避免某些字符串出现异常,这个例子怎么样?
(defn string-to-number [in] (let [s (strip-whitespace in) ;; trim f (re-find #"\d+" s)] ;; search digit else nil (if f (Integer/parseInt f) 0))) ;; if not-nil do cast (string-to-number "-") (string-to-number "10") (string-to-number "px10") (string-to-number "1200 xr")