Konwertuj ciąg na zmiennoprzecinkowy w języku Swift

101

Próbuję przekonwertować liczby pobrane z UITextField, które, jak przypuszczam, są w rzeczywistości ciągami, i przekonwertować je na zmiennoprzecinkowe, aby móc je pomnożyć.

Mam dwa, UITextfieldktóre są zadeklarowane w następujący sposób:

@IBOutlet var wage: UITextField
@IBOutlet var hour: UITextField

Kiedy użytkownik naciska przycisk UIButton, chcę obliczyć zarobki, które zarabia użytkownik, ale nie mogę, ponieważ najpierw muszę je przekonwertować na zmienne, zanim będę mógł z nich korzystać.

Wiem, jak przekonwertować je na liczbę całkowitą, wykonując następujące czynności:

var wageConversion:Int = 0
wageConversion = wage.text.toInt()!

Jednak nie mam pojęcia, jak przekonwertować je na elementy pływające.

Stephen Fox
źródło

Odpowiedzi:

200

Swift 2.0+

Teraz w Swift 2.0 możesz po prostu użyć tego, Float(Wage.text)który zwraca Float?typ. Bardziej przejrzyste niż poniższe rozwiązanie, które właśnie powraca 0.

Jeśli chcesz mieć 0wartość dla nieprawidłowego Floatz jakiegoś powodu, możesz użyć, Float(Wage.text) ?? 0który zwróci, 0jeśli nie jest prawidłowy Float.


Stare rozwiązanie

Najlepszym sposobem radzenia sobie z tym jest bezpośrednie odlewanie:

var WageConversion = (Wage.text as NSString).floatValue

Właściwie stworzyłem, extensionaby lepiej to wykorzystać:

extension String {
    var floatValue: Float {
        return (self as NSString).floatValue
    }
}

Teraz możesz po prostu zadzwonić var WageConversion = Wage.text.floatValuei zezwolić rozszerzeniu na obsługę mostu za Ciebie!

Jest to dobra implementacja, ponieważ obsługuje rzeczywiste liczby zmiennoprzecinkowe (dane wejściowe za pomocą .), a także zapobiega kopiowaniu tekstu do pola wejściowego ( 12p.34a nawet 12.12.41) przez użytkownika.

Oczywiście, jeśli Apple doda a floatValuedo Swifta, spowoduje to wyjątek, ale w międzyczasie może być miło. Jeśli dodadzą go później, wszystko, co musisz zrobić, aby zmodyfikować kod, to usunąć rozszerzenie i wszystko będzie działać bezproblemowo, ponieważ już będziesz dzwonić .floatValue!

Ponadto zmienne i stałe powinny zaczynać się od małej litery (w tym IBOutlets)

Firo
źródło
Rozszerzenie nie jest wymagane, most jest wykonywany automatycznie przez Swift, ponieważ @tom stwierdza, że ​​wszystko, czego potrzebujesz, to Wage.text.floatValue. Nie jestem pewien, czy zmieniło się to między opublikowaniem odpowiedzi a teraz, ale było to od jakiegoś czasu.
sketchyTech
3
@GoodbyeStackOverflow, używam Beta 4 i zdecydowanie nie działa. Może zmienili to w Beta 5? NSStringma floatValuerozszerzenie, ale go Stringnie ma. Uzyskaj błąd:'String' does not have member named floatValue
Firo
To może być powód. Czy na początku pliku znajduje się plik Import Foundation?
sketchyTech
Nie uważam tego za bardzo bezpieczne, przynajmniej dla standardów Swift, ponieważ jeśli ciąg nie jest liczbą, NSString.floatValue zwraca po prostu 0. Powinno to wywołać wyjątek lub przynajmniej zwrócić zero.
Ixx,
let floatValue = (Float)(Wage.text)... W Swift 2.0
TheTiger
23

Ponieważ na przykład w niektórych częściach świata zamiast przecinka używany jest przecinek. Najlepiej jest utworzyć NSNumberFormatter, aby przekonwertować ciąg na zmiennoprzecinkowy.

let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
let number = numberFormatter.numberFromString(self.stringByTrimmingCharactersInSet(Wage.text))
Dmitri Fuerle
źródło
18

Konwertuję String na Float w ten sposób:

let numberFormatter = NSNumberFormatter()
let number = numberFormatter.numberFromString("15.5")
let numberFloatValue = number.floatValue

println("number is \(numberFloatValue)") // prints "number is 15.5"
Mert
źródło
Myślę, że jest to najlepsze rozwiązanie (przynajmniej dla swift 4+), ponieważ głównym powodem jest to, że zwraca opcjonalne (w przeciwieństwie do NSString.floatValue, które po prostu zwracają, 0jeśli coś jest nie tak). Zauważ, że NSNumberFormatterzostało to zmienione NumberFormatter.
Rzym
9

Aktualizacja

Zaakceptowana odpowiedź wskazuje na bardziej aktualny sposób postępowania

Szybki 1

Oto jak Paul Hegarty pokazał się na zajęciach CS193p na Uniwersytecie Stanforda w 2015 roku:

wageConversion = NSNumberFormatter().numberFromString(wage.text!)!.floatValue

Możesz nawet utworzyć obliczoną właściwość, aby nie musieć tego robić za każdym razem

var wageValue: Float {
        get {
            return NSNumberFormatter().numberFromString(wage.text!)!.floatValue
        }
        set {
            wage.text = "\(newValue)"
        }
    }
rdprado
źródło
5

Korzystając z przyjętego rozwiązania, stwierdziłem, że moja „1.1” (przy użyciu konwersji .floatValue) zostanie przekonwertowana na 1,10000002384186, co nie było tym, czego chciałem. Jednak gdybym zamiast tego użył .doubleValue, uzyskałbym 1.1, którego chciałem.

Na przykład zamiast korzystać z zaakceptowanego rozwiązania, użyłem tego:

var WageConversion = (Wage.text as NSString).doubleValue

W moim przypadku nie potrzebowałem podwójnej precyzji, ale użycie .floatValue nie dawało mi właściwego wyniku.

Chciałem tylko dodać to do dyskusji na wypadek, gdyby ktoś inny napotkał ten sam problem.

Yjo-jo
źródło
5

Poniżej znajdziesz opcjonalny spławik, przyklej! na końcu, jeśli wiesz, że to Float, lub użyj if / let.

let wageConversion = Float(wage.text)
bandejapaisa
źródło
4

Oto adaptacja Swift 3 rozwiązania Paula Hegarty'ego z odpowiedzi rdprado, z pewnymi sprawdzeniami dodanymi do niej opcjami (zwracanie 0,0, jeśli jakakolwiek część procesu się nie powiedzie):

var wageFloat:Float = 0.0

if let wageText = wage.text {
    if let wageNumber = NumberFormatter().number(from: wageText) {
        wageFloat = wageNumber.floatValue
    }
}

Nawiasem mówiąc, wziąłem udział w zajęciach CS193p na Uniwersytecie Stanforda na Uniwersytecie iTunes, kiedy jeszcze nauczał Objective-C.

Uważam, że Paul Hegarty jest FANTASTYCZNYM instruktorem i gorąco polecam tę klasę każdemu, kto zaczyna jako programista iOS w Swift !!!

Carl Smith
źródło
1
To jest jedyna poprawna odpowiedź dla Swift 3 lub nowszego. Musisz użyć NumberFormatterznaku, aby radzić sobie z liczbami zmiennoprzecinkowymi wprowadzonymi przez użytkownika.
rmaddy
3
import Foundation
"-23.67".floatValue // => -23.67

let s = "-23.67" as NSString
s.floatValue // => -23.67
Tomek
źródło
3
Wyjaśnij, dlaczego ten kod działa. Zapobiega to kopiowaniu i wklejaniu bez zrozumienia jego działania.
rayryeng
3

Szybko 4

let Totalname = "10.0" //Now it is in string

let floatVal  = (Totalname as NSString).floatValue //Now converted to float
Raghib Arshi
źródło
3
extension String {    
    func floatValue() -> Float? {
        return Float(self)
    }
}
FlowUI. SimpleUITesting.com
źródło
1
dlaczego nie po prostu return Float(self)?
Leo Dabus
1

Masz dwie opcje, które są dość podobne (pod względem podejścia i wyniku):

// option 1:
var string_1 : String = "100"
var double_1 : Double = (string_1 as NSString).doubleValue + 99.0

// option 2: 
var string_2 : NSString = "100"
// or:  var string_2 = "100" as NSString
var number_2 : Double = string_2.doubleValue;
Michael Dorner
źródło
2
bridgeToObjectiveC () został usunięty w wersji Beta 5
carmen_munich
1

Double() buduje Double z Int, na przykład:

var convertedDouble = Double(someInt)

Zauważ, że zadziała to tylko wtedy, gdy twój tekst faktycznie zawiera liczbę. Ponieważ Wagejest to pole tekstowe, użytkownik może wprowadzić cokolwiek zechce, a to spowoduje błąd w czasie wykonywania, gdy przejdziesz do rozpakowania opcjonalnego zwróconego z toInt(). Powinieneś sprawdzić, czy konwersja powiodła się przed wymuszeniem rozpakowania.

if let wageInt = Wage.text?.toInt() {
    //we made it in the if so the conversion succeeded.
    var wageConversionDouble = Double(wageInt)
}

Edytować:

Jeśli masz pewność, że tekst będzie liczbą całkowitą, możesz zrobić coś takiego (zwróć uwagę, że textw UITextField jest również opcjonalne):

if let wageText = Wage.text {
    var wageFloat = Double(wageText.toInt()!)
}
Lanca
źródło
Cóż, zezwalam użytkownikowi tylko na wprowadzanie liczb, ponieważ klawiatura jest podkładką dziesiętną, więc nie mogą oni wprowadzać niczego innego niż liczby.
Stephen Fox
1
wageConversionFloatnigdy nie będzie zmiennoprzecinkową, ulega awarii bezpośrednio, jeśli ciąg wejściowy jest czymś w rodzaju zmiennej zmiennoprzecinkowej 234.56. jak mogłoby to być zaakceptowane / przegłosowane rozwiązanie ...?
holex
Ta odpowiedź nie działa, jeśli tekst zawiera wartość dziesiętną. Przykład - ta odpowiedź zwróci, 3jeśli pole tekstowe ma 3.5. Dzieje się tak, ponieważ tekst jest najpierw konwertowany na format an Int, a następnie Intkonwertowany na format Float.
rmaddy
1
@StephenFox Należy pamiętać, że użytkownik może wkleić tekst nienumeryczny do pola tekstowego lub może mieć zewnętrzną klawiaturę. Nigdy nie polegaj tylko na klawiaturze do wprowadzania danych.
rmaddy
w rzeczywistości działa, na liczbach całkowitych, ale nie ułamkach dziesiętnych. cyfra dziesiętna spowoduje fatalny błąd!
Miles Works
1

Znalazłem inny sposób, aby pobrać wartość wejściową UITextField i rzutować ją na float:

    var tempString:String?
    var myFloat:Float?

    @IBAction func ButtonWasClicked(_ sender: Any) {
       tempString = myUITextField.text
       myFloat = Float(tempString!)!
    }
Wayne Lampiasi
źródło
1

możesz użyć,

let wg = Float(wage.text!)

Jeśli chcesz zaokrąglić liczbę zmiennoprzecinkową do 2 miejsc po przecinku:

let wg = Float(String(format: "%.2f",wage.text!)
2rahulsk
źródło
0

Tak do tego doszedłem. Nie chciałem "przechodzić przez most", ponieważ i tak został usunięty z Xcode 6 beta 5, szybko i brudno:

extension String {

    // converting a string to double
    func toDouble() -> Double? {

        // split the string into components
        var comps = self.componentsSeparatedByString(".")

        // we have nothing
        if comps.count == 0 {
            return nil
        }
        // if there is more than one decimal
        else if comps.count > 2 {
            return nil
        }
        else if comps[0] == "" || comps[1] == "" {
            return nil
        }

        // grab the whole portion
        var whole = 0.0
        // ensure we have a number for the whole
        if let w = comps[0].toInt() {
            whole = Double(w)
        }
        else {
            return nil
        }

        // we only got the whole
        if comps.count == 1 {

            return whole

        }

        // grab the fractional
        var fractional = 0.0
        // ensure we have a number for the fractional
        if let f = comps[1].toInt() {

            // use number of digits to get the power
            var toThePower = Double(countElements(comps[1]))

            // compute the fractional portion
            fractional = Double(f) / pow(10.0, toThePower)

        }
        else {
            return nil
        }

        // return the result
        return whole + fractional
    }

    // converting a string to float
    func toFloat() -> Float? {

        if let val = self.toDouble() {
            return Float(val)
        }
        else {
            return nil
        }

    }

}


// test it out
var str = "78.001"

if let val = str.toFloat() {
    println("Str in float: \(val)")
}
else {
    println("Unable to convert Str to float")
}

// now in double
if let val = str.toDouble() {
    println("Str in double: \(val)")
}
else {
    println("Unable to convert Str to double")
}
xBACP
źródło
1
Ponieważ na przykład w niektórych częściach świata zamiast przecinka używany jest przecinek. Najlepiej jest utworzyć NSNumberFormatter, aby przekonwertować ciąg na zmiennoprzecinkowy. Spójrz na odpowiedź @DmitriFuerle
carmen_munich
@PartallyFrozenOJ Czy próbowałeś toDouble()funkcji z ciągiem „10” Mam na myśli, jeśli nie ma miejsca po przecinku. I tak się rozbije. Ponieważ w tym przypadku liczba wyniesie 1 i nie zajmujesz się tym. Rozbije się o else if comps[0] == "" || comps[1] == "". W każdym razie jesteś tak poważny w nawróceniu.
TheTiger
@PartallyFrozenOJ Ale jeśli stan był taki sam w 2014 roku. W każdym razie nie ma problemu!
TheTiger
0

W trosce o kompletność jest to rozwiązanie wykorzystujące rozszerzenie, UITextFieldktóre może również uwzględniać inne lokalizacje.

Dla Swift 3+

extension UITextField {
    func floatValue(locale : Locale = Locale.current) -> Float {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .decimal
        numberFormatter.locale = locale

        let nsNumber = numberFormatter.number(from: text!)
        return nsNumber == nil ? 0.0 : nsNumber!.floatValue
    }
}
vadian
źródło
Jako ogólne rozwiązanie powinno to prawdopodobnie zwrócić a, Float?a nie traktować niepoprawnych wartości jako 0.0. Pozwól dzwoniącemu zrobić coś takiego let val = field.floatValue ?? 0.0, jak gdyby dany przypadek traktował zły wynik jako zero.
rmaddy
0

Swift 4/5, użyj tylko Float (wartość).

let string_value : String = "123200"

let float_value : Float = Float(string_value)

print(float_value)

Odpowiedź: 123200

Krunal Patel
źródło
-1

Użyj tego:

 // get the values from text boxes
    let a:Double = firstText.text.bridgeToObjectiveC().doubleValue
    let b:Double = secondText.text.bridgeToObjectiveC().doubleValue

//  we checking against 0.0, because above function return 0.0 if it gets failed to convert
    if (a != 0.0) && (b != 0.0) {
        var ans = a + b
        answerLabel.text = "Answer is \(ans)"
    } else {
        answerLabel.text = "Input values are not numberic"
    }
Narendar Singh Saini
źródło
1
bridgeToObjectiveC () został usunięty w wersji Beta 5
carmen_munich
-4

Łatwy sposób:

// toInt returns optional that's why we used a:Int?
let a:Int? = firstText.text.toInt()
let b:Int? = secondText.text.toInt()

// check a and b before unwrapping using !
if a && b {
    var ans = a! + b!
    answerLabel.text = "Answer is \(ans)"
} else {
    answerLabel.text = "Input values are not numberic"
}

możesz użyć tego samego podejścia do innych obliczeń, mam nadzieję, że to pomoże!

Narendar Singh Saini
źródło
3
Mimo wszystko, o co prosiłfloat
Jacka