In Clojure how can I convert a String to a number?

前端 未结 13 622
别跟我提以往
别跟我提以往 2020-12-12 15:34

I have various strings, some like \"45\", some like \"45px\". How how I convert both of these to the number 45?

相关标签:
13条回答
  • 2020-12-12 15:46

    This will work on 10px or px10

    (defn parse-int [s]
       (Integer. (re-find  #"\d+" s )))
    

    it will parse the first continuous digit only so

    user=> (parse-int "10not123")
    10
    user=> (parse-int "abc10def11")
    10
    
    0 讨论(0)
  • 2020-12-12 15:47

    This isn't perfect, but here's something with filter, Character/isDigit and Integer/parseInt. It won't work for floating point numbers and it fails if there is no digit in the input, so you should probably clean it up. I hope there's a nicer way of doing this that doesn't involve so much 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)
    
    0 讨论(0)
  • 2020-12-12 15:50

    The question asks about parsing a string into a number.

    (number? 0.5)
    ;;=> true
    

    So from the above decimals ought to be parsed as well.

    Perhaps not exactly answering the question now, but for general use I think you would want to be strict about whether it is a number or not (so "px" not allowed) and let the caller handle non-numbers by returning nil:

    (defn str->number [x]
      (when-let [num (re-matches #"-?\d+\.?\d*" x)]
        (try
          (Float/parseFloat num)
          (catch Exception _
            nil))))
    

    And if Floats are problematic for your domain instead of Float/parseFloat put bigdec or something else.

    0 讨论(0)
  • How about this one to avoid an exception on certain strings ?

    (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")
    
    0 讨论(0)
  • 2020-12-12 15:54
    (defn parse-int [s]
      (Integer. (re-find #"[0-9]*" s)))
    
    user> (parse-int "10px")
    10
    user> (parse-int "10")
    10
    
    0 讨论(0)
  • 2020-12-12 15:59

    New answer

    I like snrobot's answer better. Using the Java method is simpler and more robust than using read-string for this simple use case. I did make a couple of small changes. Since the author didn't rule out negative numbers, I adjusted it to allow negative numbers. I also made it so it requires the number to start at the beginning of the string.

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

    Additionally I found that Integer/parseInt parses as decimal when no radix is given, even if there are leading zeroes.

    Old answer

    First, to parse just an integer (since this is a hit on google and it's good background information):

    You could use the reader:

    (read-string "9") ; => 9
    

    You could check that it's a number after it's read:

    (defn str->int [str] (if (number? (read-string str))))
    

    I'm not sure if user input can be trusted by the clojure reader so you could check before it's read as well:

    (defn str->int [str] (if (re-matches (re-pattern "\\d+") str) (read-string str)))
    

    I think I prefer the last solution.

    And now, to your specific question. To parse something that starts with an integer, like 29px:

    (read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
    
    0 讨论(0)
提交回复
热议问题