Bazı dizelerim var, bazıları "45", bazıları "45px" gibi. Bunların ikisini de 45 sayısına nasıl dönüştürürüm?
"9"
içine 9
, bu benim için çalıştı iyi şeydir: (Integer. "9")
.
Bazı dizelerim var, bazıları "45", bazıları "45px" gibi. Bunların ikisini de 45 sayısına nasıl dönüştürürüm?
"9"
içine 9
, bu benim için çalıştı iyi şeydir: (Integer. "9")
.
Yanıtlar:
Bu 10px
veya üzerinde çalışacakpx10
(defn parse-int [s]
(Integer. (re-find #"\d+" s )))
yalnızca ilk sürekli basamağı ayrıştırır, böylece
user=> (parse-int "10not123")
10
user=> (parse-int "abc10def11")
10
Exception in thread "main" java.lang.ClassNotFoundException: Integer.,
Snrobot'un cevabını daha çok seviyorum. Java yöntemini kullanmak, bu basit kullanım durumu için okuma dizesi kullanmaktan daha basit ve daha sağlamdır. Birkaç küçük değişiklik yaptım. Yazar negatif sayıları göz ardı etmediği için, onu negatif sayılara izin verecek şekilde ayarladım. Ayrıca, sayının dizenin başlangıcından başlamasını gerektirecek şekilde yaptım.
(defn parse-int [s]
(Integer/parseInt (re-find #"\A-?\d+" s)))
Ek olarak, Tamsayı / parseInt'in, baştaki sıfırlar olsa bile, hiçbir radix verilmediğinde ondalık olarak ayrıştırdığını buldum.
İlk olarak, sadece bir tamsayıyı ayrıştırmak için (çünkü bu google'da bir hit ve iyi bir arka plan bilgisi):
Okuyucuyu kullanabilirsiniz :
(read-string "9") ; => 9
Okunduktan sonra bir sayı olup olmadığını kontrol edebilirsiniz:
(defn str->int [str] (if (number? (read-string str))))
Kullanıcı girdisine clojure okuyucu tarafından güvenilip güvenilemeyeceğinden emin değilim, bu yüzden okumadan önce de kontrol edebilirsiniz:
(defn str->int [str] (if (re-matches (re-pattern "\\d+") str) (read-string str)))
Sanırım son çözümü tercih ediyorum.
Ve şimdi, özel sorunuza gelelim. Tam sayı ile başlayan bir şeyi ayrıştırmak için, örneğin 29px
:
(read-string (second (re-matches (re-pattern "(\\d+).*") "29px"))) ; => 29
if
bir olmalı when
senin fns hiçbir başka blok olmadığı için.
read-string
onları sekizlik olarak yorumlar: (read-string "08")
bir istisna atar. Integer/valueOf
bunları ondalık sayı olarak (Integer/valueOf "08")
değerlendirir : 8 olarak değerlendirilir.
read-string
boş bir dize veya "29px" gibi bir şey verirseniz bir istisna atacağını unutmayın
(defn parse-int [s]
(Integer. (re-find #"[0-9]*" s)))
user> (parse-int "10px")
10
user> (parse-int "10")
10
Integer/valueOf
, Integer kurucusundan ziyade genellikle kullanılması tavsiye edilir . Integer sınıfı, nesne oluşturmayı en aza indirmek için -128 ile 127 arasındaki değerleri önbelleğe alır. Tamsayı Javadoc, bunu şu
Bu benim için çok daha basit bir şekilde çalışıyor.
(okuma dizesi "123")
=> 123
read-string
aşağıdaki belgelere göre kod çalıştırabilir: clojuredocs.org/clojure.core/read-string
AFAIK, sorununuz için standart bir çözüm yok. Bence aşağıdaki gibi kullanılan bir şey clojure.contrib.str-utils2/replace
yardımcı olmalı:
(defn str2int [txt]
(Integer/parseInt (replace txt #"[a-zA-Z]" "")))
1.5
... ve aynı zamanda yerleşik clojure.string/replace
işlevi kullanmayacak.
Bu mükemmel değil, ama burada bir şey var filter
, Character/isDigit
ve Integer/parseInt
. Kayan nokta numaraları için çalışmaz ve girişte rakam yoksa başarısız olur, bu yüzden muhtemelen temizlemelisiniz. Umarım bunu yapmanın çok fazla Java içermeyen daha güzel bir yolu vardır.
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)
Muhtemelen gereksinimlere birkaç şey eklerim:
Belki şöyle bir şey:
(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
ve sonra bunu, 0 dışında bir kullanıcı tarafından sağlanan varsayılana izin veren bir çoklu yöntem yapmak için bonus puanlar.
Snrobot'un cevabını genişleterek:
(defn string->integer [s]
(when-let [d (re-find #"-?\d+" s)] (Integer. d)))
Bu sürümler, girişte bir istisna oluşturmak yerine rakam yoksa sıfır döndürür.
Sorum, adın "str-> int" olarak kısaltılmasının kabul edilebilir olup olmadığı veya bunun gibi şeylerin her zaman tam olarak belirtilmesi gerekip gerekmediğidir.
Ayrıca (re-seq)
işlevin kullanılması , dönüş değerini, sırayla giriş dizesinde bulunan tüm sayıları içeren bir dizeye genişletebilir:
(defn convert-to-int [s]
(->> (re-seq #"\d" s)
(apply str)
(Integer.)))
(convert-to-int "10not123")
=> 10123
(type *1)
=> java.lang.Integer
Soru, bir dizeyi sayıya ayrıştırmayı sorar.
(number? 0.5)
;;=> true
Dolayısıyla, yukarıdaki ondalık sayılardan da ayrıştırılması gerekir.
Belki şu anda soruyu tam olarak yanıtlamıyor olabilirim, ancak genel kullanım için bunun bir sayı olup olmadığı konusunda katı olmak isteyeceğinizi (bu nedenle "piksel" e izin verilmez) ve arayanın sıfır döndürerek sayı olmayanları işlemesine izin vereceğinizi düşünüyorum:
(defn str->number [x]
(when-let [num (re-matches #"-?\d+\.?\d*" x)]
(try
(Float/parseFloat num)
(catch Exception _
nil))))
Ve eğer Floats, alanınız için Float/parseFloat
koymak bigdec
veya başka bir şey yerine sorunluysa .
Daha normal bir String hazır bilgisini bir sayıya, yani başka sayısal olmayan karakterleri olmayan bir dizeye ayrıştırmak isteyen herkes için. Bunlar en iyi iki yaklaşımdır:
Java birlikte çalışmasının kullanılması:
(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")
Bu, kullanım durumunuz için önemli olduğunda, numarayı ayrıştırmak istediğiniz türü tam olarak kontrol etmenizi sağlar.
Clojure EDN okuyucunun kullanılması:
(require '[clojure.edn :as edn])
(edn/read-string "333")
Kullanılarak farklı read-string
mesafede clojure.core
olan güvenilir olmayan girişi kullanımı güvenli değildir, edn/read-string
örneğin kullanıcı girdisi gibi güvenilir olmayan giriş çalıştırmak için güvenlidir.
Türler üzerinde belirli bir denetime sahip olmanız gerekmiyorsa, bu genellikle Java birlikte çalışmasından daha uygundur. Clojure'un aşağıdaki gibi ayrıştırabileceği herhangi bir sayıyı ayrıştırabilir:
;; Ratios
(edn/read-string "22/7")
;; Hexadecimal
(edn/read-string "0xff")
Tam liste burada: https://www.rubberducking.com/2019/05/clojure-for-non-clojure-programmers.html#numbers
Basit durumlarda, yukarıda belirtildiği gibi ilk rakam dizisini çıkarmak için bir normal ifade kullanabilirsiniz.
Daha karmaşık bir durumunuz varsa, InstaParse kütüphanesini kullanmak isteyebilirsiniz:
(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)
kullanıcıya yaptırmak yerine neden kullanıyorsunuz (:require [tupelo.core :refer :all])
?
refer-tupelo
refer-clojure
her şeyi içermediği için modellenmiştir (:require [tupelo.core :refer :all])
.