В Clojure, как я могу преобразовать строку в число? - PullRequest
119 голосов
/ 11 апреля 2011

У меня есть различные строки, некоторые как "45", некоторые как "45px".Как мне конвертировать оба этих числа в число 45?

Ответы [ 12 ]

79 голосов
/ 08 февраля 2012

Новый ответ

Мне больше нравится ответ снобота.Использование метода Java проще и надежнее, чем использование read-string для этого простого варианта использования.Я сделал пару небольших изменений.Поскольку автор не исключил отрицательных чисел, я настроил его, чтобы разрешить отрицательные числа.Я также сделал это так, что для начала нужно, чтобы число начиналось в начале строки.

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

Кроме того, я обнаружил, что Integer / parseInt анализирует как десятичное число, когда не задано основание, даже если есть начальные нули.

Старый ответ

Сначала проанализируем только целое число (так как это хит в Google и это хорошая справочная информация):

Вы можетеиспользуйте reader :

(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:

(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
76 голосов
/ 20 сентября 2012

Это будет работать на 10px или px10

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

будет анализировать только первую непрерывную цифру, поэтому

user=> (parse-int "10not123")
10
user=> (parse-int "abc10def11")
10
28 голосов
/ 11 апреля 2011
(defn parse-int [s]
  (Integer. (re-find #"[0-9]*" s)))

user> (parse-int "10px")
10
user> (parse-int "10")
10
15 голосов
/ 08 марта 2017

Это работает в repl для меня, гораздо более прямо вперед.

(чтение строки "123")

=> 123

9 голосов
/ 11 апреля 2011

AFAIK нет стандартного решения вашей проблемы. Я думаю, что-то вроде следующего, который использует clojure.contrib.str-utils2/replace, должно помочь:

(defn str2int [txt]
  (Integer/parseInt (replace txt #"[a-zA-Z]" "")))
7 голосов
/ 11 апреля 2011

Это не идеально, но вот что-то с 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)
3 голосов
/ 23 апреля 2017

Вопрос касается разбора строки в число.

(number? 0.5)
;;=> true

Так что из вышеприведенных десятичных чисел следует также разбирать.

Возможно, не совсем отвечая на вопрос сейчас, но для общего использования, я думаю, вы хотели бы быть строгим в отношении того, является ли это число или нет (поэтому «px» не допускается), и позволить вызывающей стороне обрабатывать не числа, возвращая ноль :

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

А если Float проблематичен для вашего домена вместо Float/parseFloat, поставьте bigdec или что-то еще.

2 голосов
/ 08 сентября 2015

Также с помощью функции (re-seq) можно расширить возвращаемое значение до строки, содержащей все числа, существующие во входной строке, в следующем порядке:

(defn convert-to-int [s] (->> (re-seq #"\d" s) (apply str) (Integer.)))

(convert-to-int "10not123") => 10123

(type *1) => java.lang.Integer

2 голосов
/ 02 августа 2015

Расширение ответа snrobot:

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

В этих версиях возвращается ноль, если во входных данных нет цифр, а не выдается исключение.

Мой вопрос заключается в том, допустимо ли сокращениеимя для "str-> int", или если такие вещи всегда должны быть полностью указаны.

2 голосов
/ 28 февраля 2015

Я бы, наверное, добавил к требованиям несколько вещей:

  • Должен начинаться с цифры
  • Должен терпеть пустые входы
  • Допускает передачу любого объекта (стандартно toString)

Может быть, что-то вроде:

(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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...