Hızlı bir dilde BMI programı yazmaya çalışıyorum. Ve ben bu sorunu var: bir dize bir Double dönüştürmek nasıl?
Objective-C'de şöyle yapabilirim:
double myDouble = [myString doubleValue];
Ama bunu Swift dilinde nasıl başarabilirim?
Hızlı bir dilde BMI programı yazmaya çalışıyorum. Ve ben bu sorunu var: bir dize bir Double dönüştürmek nasıl?
Objective-C'de şöyle yapabilirim:
double myDouble = [myString doubleValue];
Ama bunu Swift dilinde nasıl başarabilirim?
Yanıtlar:
Swift 4.2+ Dize İkili
Dize ve sayısal türler (Double, Float, Int) arasında dönüştürme yapmak için yeni tür başlatıcıları kullanmalısınız. Dize bir sayı değilse, doğru değere veya nil değerine sahip bir İsteğe bağlı tür (Double?) Döndürür.
Not: Değer dönüştürülemiyorsa 0 döndürdüğü için NSString doubleValue özelliği önerilmez (örn: hatalı kullanıcı girişi).
let lessPrecisePI = Float("3.14")
let morePrecisePI = Double("3.1415926536")
let invalidNumber = Float("alphabet") // nil, not a valid number
İf / let kullanarak değerleri kullanmak için paketini açın
if let cost = Double(textField.text!) {
print("The user entered a value price of \(cost)")
} else {
print("Not a valid number: \(textField.text!)")
}
NumberFormatter
Sınıfı kullanarak biçimlendirilmiş sayıları ve para birimini dönüştürebilirsiniz .
let formatter = NumberFormatter()
formatter.locale = Locale.current // USA: Locale(identifier: "en_US")
formatter.numberStyle = .decimal
let number = formatter.number(from: "9,999.99")
Para birimi biçimleri
let usLocale = Locale(identifier: "en_US")
let frenchLocale = Locale(identifier: "fr_FR")
let germanLocale = Locale(identifier: "de_DE")
let englishUKLocale = Locale(identifier: "en_GB") // United Kingdom
formatter.numberStyle = .currency
formatter.locale = usLocale
let usCurrency = formatter.number(from: "$9,999.99")
formatter.locale = frenchLocale
let frenchCurrency = formatter.number(from: "9999,99€")
// Note: "9 999,99€" fails with grouping separator
// Note: "9999,99 €" fails with a space before the €
formatter.locale = germanLocale
let germanCurrency = formatter.number(from: "9999,99€")
// Note: "9.999,99€" fails with grouping separator
formatter.locale = englishUKLocale
let englishUKCurrency = formatter.number(from: "£9,999.99")
Dize'i Çift türe (ve para birimine) dönüştürme hakkında blog yayınımda daha fazla bilgi edinin .
Swift 2 Güncelleme
Birçok cevaplar belirttiği gibi olmayan sayı değerleri için 0 verir, çünkü NSString çifte değeri çok güvenli değildir (daha deyimsel ve güvenli bir şekilde bunu yapmak için izin yeni failable ilklendiriciler Bu araçlar. Olduklarını doubleValue
arasında "foo"
ve "0"
vardır aynısı.)
let myDouble = Double(myString)
Bu isteğe bağlı bir değer döndürür, bu nedenle 0 döndürdüğü "foo"
yerlerden geçmek gibi durumlarda doubleValue
, faililable intializer geri döner nil
. Bir kullanabilir guard
, if-let
ya da map
işlemek içinOptional<Double>
Orijinal Gönderi: NSString yapıcısını kabul edilen cevap önerileri gibi kullanmanıza gerek yoktur. Basitçe şu şekilde köprü yapabilirsiniz:
(swiftString as NSString).doubleValue
- [NSString doubleValue]
olduğu Double
tam tersine, ani olarak Double?
( Optional<Double>
). Bu, dokümanlarda toInt()
döndürülen Int?
ve "... -" [- +]? [0-9] + "normal ifadesiyle eşleşen dizeleri kabul ettiğini belirten Swift String işlevinden farklıdır .
.toInt()
daha iyi olurdu. Ancak, bu tam olarak aynı şeyi nasıl yapacağına, ancak Swift'te bir cevaptı.
Double.init?(_ text: String)
artık kullanılabilir bir başlatıcı var.
Biraz daha fazla Swift hissi için, kullanmak , dizeye bir değer içermediğinde (örneğin "test" geri dönmeyecektir ) , NSFormatter()
yayınlamayı önler NSString
ve geri döner .nil
Double
0.0
let double = NSNumberFormatter().numberFromString(myString)?.doubleValue
Alternatif olarak, Swift'in String
türünü genişletmek :
extension String {
func toDouble() -> Double? {
return NumberFormatter().number(from: self)?.doubleValue
}
}
ve şöyle kullanın toInt()
:
var myString = "4.2"
var myDouble = myString.toDouble()
Bu isteğe bağlı döndürür Double?
.
Zorla açılmayla:
println("The value is \(myDouble!)") // prints: The value is 4.2
veya if let ifadesiyle:
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
Güncelleme: Yerelleştirme için NSFormatter'a aşağıdaki gibi yerel ayarları uygulamak çok kolaydır:
let formatter = NSNumberFormatter()
formatter.locale = NSLocale(localeIdentifier: "fr_FR")
let double = formatter.numberFromString("100,25")
Son olarak, NSNumberFormatterCurrencyStyle
dizenin para birimi sembolünü içerdiği para birimleriyle çalışıyorsanız biçimlendiriciyi kullanabilirsiniz .
Burada başka bir seçenek bunu bir dönüştürmek NSString
ve kullanmaktır:
let string = NSString(string: mySwiftString)
string.doubleValue
(swiftString as NSString).doubleValue
İşte bir Swift dizesinde doubleValue () yöntemini çağırmanıza ve bir çift geri almanıza olanak tanıyan bir uzantı yöntemi (örnek çıktı önce gelir)
println("543.29".doubleValue())
println("543".doubleValue())
println(".29".doubleValue())
println("0.29".doubleValue())
println("-543.29".doubleValue())
println("-543".doubleValue())
println("-.29".doubleValue())
println("-0.29".doubleValue())
//prints
543.29
543.0
0.29
0.29
-543.29
-543.0
-0.29
-0.29
Uzantı yöntemi şöyledir:
extension String {
func doubleValue() -> Double
{
let minusAscii: UInt8 = 45
let dotAscii: UInt8 = 46
let zeroAscii: UInt8 = 48
var res = 0.0
let ascii = self.utf8
var whole = [Double]()
var current = ascii.startIndex
let negative = current != ascii.endIndex && ascii[current] == minusAscii
if (negative)
{
current = current.successor()
}
while current != ascii.endIndex && ascii[current] != dotAscii
{
whole.append(Double(ascii[current] - zeroAscii))
current = current.successor()
}
//whole number
var factor: Double = 1
for var i = countElements(whole) - 1; i >= 0; i--
{
res += Double(whole[i]) * factor
factor *= 10
}
//mantissa
if current != ascii.endIndex
{
factor = 0.1
current = current.successor()
while current != ascii.endIndex
{
res += Double(ascii[current] - zeroAscii) * factor
factor *= 0.1
current = current.successor()
}
}
if (negative)
{
res *= -1;
}
return res
}
}
Hata kontrolü yok, ancak ihtiyacınız varsa ekleyebilirsiniz.
Swift 1.1 itibariyle, doğrudan geçebilir String
için const char *
parametre.
import Foundation
let str = "123.4567"
let num = atof(str) // -> 123.4567
atof("123.4567fubar") // -> 123.4567
Kullanımdan kaldırılmayı sevmiyorsanız atof
:
strtod("765.4321", nil) // -> 765.4321
Bir uyarı: dönüşüm davranışı, NSString.doubleValue
.
atof
ve ön ekli onaltılık dizeyi strtod
kabul edin 0x
:
atof("0xffp-2") // -> 63.75
atof("12.3456e+2") // -> 1,234.56
atof("nan") // -> (not a number)
atof("inf") // -> (+infinity)
.doubleValue
Davranışı tercih ederseniz , CFString
köprülemeyi kullanmaya devam edebiliriz :
let str = "0xff"
atof(str) // -> 255.0
strtod(str, nil) // -> 255.0
CFStringGetDoubleValue(str) // -> 0.0
(str as NSString).doubleValue // -> 0.0
NSString
.
Swift 2.0'da en iyi yol bir Objective-C geliştiricisi gibi düşünmekten kaçınmaktır. Bu nedenle, "bir String'i bir Double'e dönüştürmemelisiniz" ancak "bir String'den bir Double başlatmalısınız". Apple dokümanı buraya: https://developer.apple.com/library/ios//documentation/Swift/Reference/Swift_Double_Structure/index.html#//apple_ref/swift/structctr/Double/s:FSdcFMSdFSSGSqSd_
Varsayılan bir değer ayarlamak için nil birleştirme operatörünü (??) kullanabilmeniz için isteğe bağlı bir başlangıçtır. Misal:
let myDouble = Double("1.1") ?? 0.0
Double.init?(_ text: String)
Swift 2.0'da kullanıma sunuluyor. Bundan bahsetmelisin. Buradaki diğer cevaplar, insanların Objective-C geliştiricileri gibi düşündükleri için değil, bu başlatıcıyı daha önce mevcut olmadığı için.
On SWIFT 3 , şunları kullanabilirsiniz:
if let myDouble = NumberFormatter().number(from: yourString)?.doubleValue {
print("My double: \(myDouble)")
}
Not: - Bir dize sayısal rakamlar veya yerel ayara uygun grup veya ondalık ayırıcılar dışında herhangi bir karakter içeriyorsa, ayrıştırma başarısız olur. - Bir dizedeki ön veya arka boşluk ayırıcı karakterleri yok sayılır. Örneğin, “5”, “5” ve “5” dizelerinin tümü 5 sayısını üretir.
Belgelerden alınmıştır: https://developer.apple.com/reference/foundation/numberformatter/1408845-number
Bunu dene:
var myDouble = myString.bridgeToObjectiveC().doubleValue
println(myDouble)
NOT
Beta 5'te kaldırıldı. Bu artık çalışmıyor mu?
@Ryu'nun cevabı üzerine inşa ediliyor
Noktaların ayırıcılar olarak kullanıldığı bir ülkede olduğunuz sürece çözümü harika. Varsayılan NSNumberFormatter
olarak aygıtların yerel ayarlarını kullanır. Bu nedenle, sayı ayırıcılar olarak noktalar kullanırsa (normalde durum budur), varsayılan ayırıcı olarak virgül kullanılan tüm ülkelerde (@PeterK olarak belirtilen. Dahil) başarısız olur. Bu NSNumberFormatter öğesinin yerel ayarını ABD olarak ayarlamak ve bu nedenle ayırıcı olarak satırları kullanmak için noktaları kullanın
return NSNumberFormatter().numberFromString(self)?.doubleValue
ile
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
Böylece tam kod
extension String {
func toDouble() -> Double? {
let numberFormatter = NSNumberFormatter()
numberFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
return numberFormatter.numberFromString(self)?.doubleValue
}
}
Bunu kullanmak için "Your text goes here".toDouble()
Bu, isteğe bağlı olarak Double?
@Ryu'nun belirttiği gibi, açılmayı zorlayabilirsiniz:
println("The value is \(myDouble!)") // prints: The value is 4.2
veya bir if let
ifade kullanın :
if let myDouble = myDouble {
println("The value is \(myDouble)") // prints: The value is 4.2
}
NumberFormatter().number(from: myString)?.doubleValue
bunu dene
let str:String = "111.11"
let tempString = (str as NSString).doubleValue
print("String:-",tempString)
Hızlı: 4 ve 5
Bunu yapmanın iki yolu vardır:
Dize -> Int -> Çift:
let strNumber = "314"
if let intFromString = Int(strNumber){
let dobleFromInt = Double(intFromString)
print(dobleFromInt)
}
String -> NSString -> Çift
let strNumber1 = "314"
let NSstringFromString = NSString(string: strNumber1)
let doubleFromNSString = NSstringFromString.doubleValue
print(doubleFromNSString)
Kodu ihtiyacınıza göre istediğiniz şekilde kullanın.
Lütfen oyun alanında kontrol edin!
let sString = "236.86"
var dNumber = NSNumberFormatter().numberFromString(sString)
var nDouble = dNumber!
var eNumber = Double(nDouble) * 3.7
Bu arada Xcode'umda
.toDouble () - mevcut değil
.doubleValue sayısal olmayan dizelerden 0.0 değeri oluştur ...
1.
let strswift = "12"
let double = (strswift as NSString).doubleValue
2.
var strswift= "10.6"
var double : Double = NSString(string: strswift).doubleValue
Senin için bu yardım olabilir.
Daha önce de belirtildiği gibi, bunu başarmanın en iyi yolu doğrudan dökümdür:
(myString as NSString).doubleValue
Bundan yola çıkarak, kaygan bir yerel Swift String uzantısı yapabilirsiniz:
extension String {
var doubleValue: Double {
return (self as NSString).doubleValue
}
}
Bu doğrudan kullanmanıza izin verir:
myString.doubleValue
Hangi döküm sizin için yapacak. Apple doubleValue
yerel String'e bir eklerse, sadece uzantıyı kaldırmanız gerekir ve kodunuzun geri kalanı otomatik olarak iyi derlenir!
SWIFT 3
Temizlemek için bugünlerde varsayılan bir yöntem var:
public init?(_ text: String)
bir Double
sınıfa.
Tüm sınıflar için kullanılabilir.
let c = Double("-1.0")
let f = Double("0x1c.6")
let i = Double("inf")
, vb.
İsteğe bağlı yerel ayarlı uzantı
Hızlı 2.2
extension String {
func toDouble(locale: NSLocale? = nil) -> Double? {
let formatter = NSNumberFormatter()
if let locale = locale {
formatter.locale = locale
}
return formatter.numberFromString(self)?.doubleValue
}
}
Hızlı 3.1
extension String {
func toDouble(_ locale: Locale) -> Double {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = locale
formatter.usesGroupingSeparator = true
if let result = formatter.number(from: self)?.doubleValue {
return result
} else {
return 0
}
}
}
StringEx kullanabilirsiniz . String
Dize-sayı dönüşümleri dahil olmak üzere uzanır toDouble()
.
extension String {
func toDouble() -> Double?
}
Dizeyi doğrular ve çifte dönüştürülemezse başarısız olur.
Misal:
import StringEx
let str = "123.45678"
if let num = str.toDouble() {
println("Number: \(num)")
} else {
println("Invalid string")
}
Hızlı 4
extension String {
func toDouble() -> Double {
let nsString = self as NSString
return nsString.doubleValue
}
}
Swift 2.0'da bu kodu kullanın
let strWithFloat = "78.65"
let floatFromString = Double(strWithFloat)
Kullanılması Scanner
bazı durumlarda bir dize numaraları çıkarma çok uygun bir yoldur. Ve neredeyse NumberFormatter
farklı sayı biçimleri ve yerel ayarları çözmek ve uğraşmak kadar güçlüdür . Farklı ondalık ve grup ayırıcıları ile sayıları ve para birimlerini ayıklayabilir.
import Foundation
// The code below includes manual fix for whitespaces (for French case)
let strings = ["en_US": "My salary is $9,999.99",
"fr_FR": "Mon salaire est 9 999,99€",
"de_DE": "Mein Gehalt ist 9999,99€",
"en_GB": "My salary is £9,999.99" ]
// Just for referce
let allPossibleDecimalSeparators = Set(Locale.availableIdentifiers.compactMap({ Locale(identifier: $0).decimalSeparator}))
print(allPossibleDecimalSeparators)
for str in strings {
let locale = Locale(identifier: str.key)
let valStr = str.value.filter{!($0.isWhitespace || $0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
Ancak, sözcük ayırıcıları olarak düşünülebilen ayırıcılarla ilgili sorunlar vardır.
// This doesn't work. `Scanner` just ignores grouping separators because scanner tends to seek for multiple values
// It just refuses to ignore spaces or commas for example.
let strings = ["en_US": "$9,999.99", "fr_FR": "9999,99€", "de_DE": "9999,99€", "en_GB": "£9,999.99" ]
for str in strings {
let locale = Locale(identifier: str.key)
let sc = Scanner(string: str.value)
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted.union(CharacterSet(charactersIn: locale.groupingSeparator ?? ""))
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: \(locale.groupingSeparator ?? "") . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// sc.scanDouble(representation: Scanner.NumberRepresentation) could help if there were .currency case
Yerel ayarı otomatik olarak algılamakta sorun yoktur. "Mon salaire est 9 999,99 €" dizesinde Fransızca yerel ayarında groupingSeparator bir boşluk değildir, ancak tam olarak boşluk olarak işlenebilir (burada değil). Bu nedenle, aşağıdaki kod, !$0.isWhitespace
karakterler filtrelenmeden iyi çalışır .
let stringsArr = ["My salary is $9,999.99",
"Mon salaire est 9 999,99€",
"Mein Gehalt ist 9.999,99€",
"My salary is £9,999.99" ]
let tagger = NSLinguisticTagger(tagSchemes: [.language], options: Int(NSLinguisticTagger.Options.init().rawValue))
for str in stringsArr {
tagger.string = str
let locale = Locale(identifier: tagger.dominantLanguage ?? "en")
let valStr = str.filter{!($0 == Character(locale.groupingSeparator ?? ""))}
print("Value String", valStr)
let sc = Scanner(string: valStr)
// we could do this more reliably with `filter` as well
sc.charactersToBeSkipped = CharacterSet.decimalDigits.inverted
sc.locale = locale
print("Locale \(locale.identifier) grouping separator: |\(locale.groupingSeparator ?? "")| . Decimal separator: \(locale.decimalSeparator ?? "")")
while !(sc.isAtEnd) {
if let val = sc.scanDouble() {
print(val)
}
}
}
// Also will fail if groupingSeparator == decimalSeparator (but don't think it's possible)
benim sorun virgül oldu bu yüzden bunu bu şekilde çözmek:
extension String {
var doubleValue: Double {
return Double((self.replacingOccurrences(of: ",", with: ".") as NSString).doubleValue)
}
}
var stringValue = "55"
var convertToDouble = Double((stringValue as NSString).doubleValue)
myString.doubleValue tarafından elde edilecek CDouble değerini kullanabiliriz