"45"와 같은 "45px"와 같은 다양한 문자열이 있습니다. 이 두 가지를 어떻게 숫자 45로 변환합니까?
"9"
로 9
, 이것은 나를 위해 일한 가장 좋은 방법이다 (Integer. "9")
.
"45"와 같은 "45px"와 같은 다양한 문자열이 있습니다. 이 두 가지를 어떻게 숫자 45로 변환합니까?
"9"
로 9
, 이것은 나를 위해 일한 가장 좋은 방법이다 (Integer. "9")
.
답변:
이 작업 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.,
나는 snrobot의 대답이 더 좋습니다. Java 메소드를 사용하는 것이이 간단한 사용 사례에 대해 읽기 문자열을 사용하는 것보다 더 간단하고 강력합니다. 몇 가지 작은 변경을했습니다. 저자는 음수를 배제하지 않았으므로 음수를 허용하도록 조정했습니다. 또한 문자열의 시작 부분에서 숫자를 시작해야합니다.
(defn parse-int [s]
(Integer/parseInt (re-find #"\A-?\d+" s)))
또한 선행 0이 있더라도 기수가 주어지지 않으면 Integer / parseInt가 10 진수로 구문 분석된다는 것을 알았습니다.
먼저 정수를 구문 분석하려면 (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
:
(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
if
있어야합니다 when
.
read-string
그것들을 8 진수로 해석합니다 : (read-string "08")
예외를 던집니다. Integer/valueOf
소수점 이하 자릿수로 처리합니다. (Integer/valueOf "08")
8로 평가됩니다.
read-string
당신이 그것을 "29px"와 같은 빈 문자열이나 뭐 줄 경우 예외가 발생합니다
(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은 이것을 다음 게시물과 같이 설명합니다 : stackoverflow.com/a/2974852/871012
이것은 훨씬 더 직설적으로 나를 위해 작동합니다.
(읽기 문자열 "123")
=> 123
read-string
문서마다 코드를 실행할 수 있습니다. clojuredocs.org/clojure.core/read-string
AFAIK 문제에 대한 표준 솔루션이 없습니다. 을 사용하는 다음과 같은 clojure.contrib.str-utils2/replace
것이 도움이 될 것이라고 생각합니다 .
(defn str2int [txt]
(Integer/parseInt (replace txt #"[a-zA-Z]" "")))
1.5
그것을 던질 때까지 작동 하며 내장 clojure.string/replace
기능 을 사용하지 않습니다 .
완벽하지는 않지만 여기에 뭔가가 있습니다. 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)
아마도 요구 사항에 몇 가지 사항을 추가 할 것입니다.
어쩌면 다음과 같은 것 :
(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
그런 다음이 방법을 다중 방법으로 만들면 보너스 포인트가 아닌 사용자 제공 기본값을 사용할 수 있습니다.
또한 (re-seq)
함수를 사용하면 반환 값을 입력 문자열에 존재하는 모든 숫자가 포함 된 문자열로 순서대로 확장 할 수 있습니다.
(defn convert-to-int [s]
(->> (re-seq #"\d" s)
(apply str)
(Integer.)))
(convert-to-int "10not123")
=> 10123
(type *1)
=> java.lang.Integer
이 질문은 문자열을 숫자로 파싱하는 것에 대해 묻습니다.
(number? 0.5)
;;=> true
따라서 위의 소수점부터 파싱해야합니다.
아마도 지금 질문에 정확하게 대답하지는 않지만 일반적으로 사용하기 위해 숫자인지 아닌지에 대해 엄격하고 (그렇지 않으면 "px"를 허용하지 않음) nil을 반환하여 호출자가 숫자가 아닌 숫자를 처리하도록 할 것이라고 생각합니다.
(defn str->number [x]
(when-let [num (re-matches #"-?\d+\.?\d*" x)]
(try
(Float/parseFloat num)
(catch Exception _
nil))))
그리고 수레는 대신 도메인에 문제가있는 경우 Float/parseFloat
풋 bigdec
또는 뭔가 다른.
더 일반적인 문자열 리터럴을 숫자, 즉 숫자가 아닌 다른 문자가없는 문자열로 구문 분석하려는 다른 사람. 다음은 두 가지 가장 좋은 방법입니다.
Java interop 사용 :
(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")
사용 달리 read-string
에서 clojure.core
어떤 신뢰할 수없는 입력을 사용하는 것이 안전하지 않습니다, edn/read-string
같은 사용자 입력로 신뢰할 수없는 입력에서 실행하는 것이 안전합니다.
유형을 구체적으로 제어 할 필요가없는 경우 Java interop보다 더 편리합니다. 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
간단한 경우에는 위에서 언급 한 것처럼 정규식을 사용하여 첫 번째 자릿수를 뽑을 수 있습니다.
보다 복잡한 상황이 발생하면 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"))))
(t/refer-tupelo)
사용자가 수행 하는 대신 왜 사용 합니까 (:require [tupelo.core :refer :all])
?
refer-tupelo
refer-clojure
방법은 모든 것을 포함하지 않는다는 점 에서을 모델로 (:require [tupelo.core :refer :all])
합니다.