Convertir une chaîne en flottant dans Swift

101

J'essaie de convertir des nombres tirés d'un UITextField, qui je suppose, sont en fait des chaînes, et de les convertir en Float, afin que je puisse les multiplier.

J'ai deux UITextfields qui sont déclarés comme suit:

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

Lorsque l'utilisateur appuie sur un UIButton, je veux calculer le salaire qu'il gagne, mais je ne peux pas, car je dois d'abord les convertir en flottants, avant de pouvoir les utiliser.

Je sais comment les convertir en entier en faisant ceci:

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

Cependant, je ne sais pas comment les convertir en flotteurs.

Stephen Fox
la source

Réponses:

200

Swift 2.0+

Maintenant, avec Swift 2.0, vous pouvez simplement utiliser Float(Wage.text)qui renvoie un Float?type. Plus clair que la solution ci-dessous qui revient juste 0.

Si vous voulez une 0valeur pour un invalide Floatpour une raison quelconque, vous pouvez utiliser Float(Wage.text) ?? 0qui retournera 0si ce n'est pas un valide Float.


Ancienne solution

La meilleure façon de gérer cela est la diffusion directe:

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

J'ai en fait créé un extensionpour mieux utiliser cela aussi:

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

Maintenant, vous pouvez simplement appeler var WageConversion = Wage.text.floatValueet permettre à l'extension de gérer le pont pour vous!

C'est une bonne implémentation car elle peut gérer les flottants réels (entrée avec .) et aidera également à empêcher l'utilisateur de copier du texte dans votre champ de saisie ( 12p.34ou même 12.12.41).

Évidemment, si Apple ajoute un floatValueà Swift, cela lèvera une exception, mais cela peut être agréable en attendant. S'ils l'ajoutent plus tard, tout ce que vous avez à faire pour modifier votre code est de supprimer l'extension et tout fonctionnera de manière transparente, car vous appellerez déjà .floatValue!

En outre, les variables et les constantes doivent commencer par une minuscule (y compris IBOutlets)

Firo
la source
L'extension n'est pas requise, le pont est fait automatiquement par Swift, car @tom indique que tout ce dont vous avez besoin est Wage.text.floatValue. Je ne sais pas si cela a changé entre la publication de la réponse et maintenant, mais cela fait un moment.
sketchyTech
3
@GoodbyeStackOverflow, j'utilise Beta 4 et cela ne fonctionne certainement pas. Peut-être qu'ils l'ont changé dans la bêta 5? NSStringa une floatValueextension mais Stringpas. Obtenir l'erreur:'String' does not have member named floatValue
Firo
Cela pourrait être la raison. De plus, avez-vous import Foundation en haut de votre fichier?
sketchyTech
Je ne considère pas cela très sûr, du moins pour les standards Swift, car si la chaîne n'est pas un nombre, NSString.floatValue renvoie simplement 0. Cela devrait déclencher une exception ou au moins renvoyer nil.
Ixx
let floatValue = (Float)(Wage.text)... dans Swift 2.0
TheTiger
23

Parce que dans certaines régions du monde, par exemple, une virgule est utilisée à la place d'un décimal. Il est préférable de créer un NSNumberFormatter pour convertir une chaîne en float.

let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
let number = numberFormatter.numberFromString(self.stringByTrimmingCharactersInSet(Wage.text))
Dmitri Fuerle
la source
18

Je convertis String en Float de cette manière:

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

println("number is \(numberFloatValue)") // prints "number is 15.5"
Mert
la source
Je pense que c'est la meilleure solution (au moins pour swift 4+), la raison principale étant qu'elle renvoie une option (par opposition à NSString.floatValue, qui revient simplement 0si quelque chose ne va pas.). Notez que cela a NSNumberFormatterété changé NumberFormatter.
Rom
9

Mettre à jour

La réponse acceptée montre une façon de faire plus à jour

Swift 1

Voici comment Paul Hegarty l'a montré dans la classe CS193p de Stanford en 2015:

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

Vous pouvez même créer une propriété calculée pour ne pas avoir à faire cela à chaque fois

var wageValue: Float {
        get {
            return NSNumberFormatter().numberFromString(wage.text!)!.floatValue
        }
        set {
            wage.text = "\(newValue)"
        }
    }
rdprado
la source
5

En utilisant la solution acceptée, j'ai découvert que mon "1.1" (lors de l'utilisation de la conversion .floatValue) serait converti en 1.10000002384186, ce qui n'était pas ce que je voulais. Cependant, si j'utilisais le .doubleValue à la place, j'obtiendrais le 1.1 que je voulais.

Ainsi, par exemple, au lieu d'utiliser la solution acceptée, j'ai utilisé ceci à la place:

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

Dans mon cas, je n'avais pas besoin de double précision, mais l'utilisation de .floatValue ne me donnait pas le résultat correct.

Je voulais juste ajouter ceci à la discussion au cas où quelqu'un d'autre aurait rencontré le même problème.

Yjo-jo
la source
5

Ci-dessous vous donnera un flotteur en option, collez un! à la fin si vous savez qu'il s'agit d'un Float, ou utilisez if / let.

let wageConversion = Float(wage.text)
bandejapaisa
la source
4

Voici une adaptation Swift 3 de la solution de Paul Hegarty à partir de la réponse de rdprado, avec quelques vérifications d'options ajoutées (renvoyant 0.0 si une partie du processus échoue):

var wageFloat:Float = 0.0

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

Au fait, j'ai suivi le cours CS193p de Stanford en utilisant iTunes University alors qu'il enseignait encore Objective-C.

J'ai trouvé que Paul Hegarty était un instructeur FANTASTIQUE, et je recommanderais vivement le cours à tous ceux qui débutent en tant que développeur iOS dans Swift !!!

Carl Smith
la source
1
C'est la seule bonne réponse pour Swift 3 ou version ultérieure. Vous devez utiliser a NumberFormatterpour traiter les nombres à virgule flottante saisis par l'utilisateur.
rmaddy
3
import Foundation
"-23.67".floatValue // => -23.67

let s = "-23.67" as NSString
s.floatValue // => -23.67
à M
la source
3
Expliquez pourquoi ce code fonctionne. Cela empêche le copier-coller sans comprendre son fonctionnement.
rayryeng
3

Dans Swift 4

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

let floatVal  = (Totalname as NSString).floatValue //Now converted to float
Raghib Arshi
la source
3
extension String {    
    func floatValue() -> Float? {
        return Float(self)
    }
}
FlowUI. SimpleUITesting.com
la source
1
pourquoi pas simplement return Float(self)?
Leo Dabus
1

Vous avez deux options assez similaires (par l'approche et le résultat):

// 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
la source
2
bridgeToObjectiveC () a été supprimé dans la bêta 5
carmen_munich
1

Double() construit un Double à partir d'un Int, comme ceci:

var convertedDouble = Double(someInt)

Notez que cela ne fonctionnera que si votre texte contient réellement un nombre. Puisqu'il Wages'agit d'un champ de texte, l'utilisateur peut entrer ce qu'il veut et cela déclenchera une erreur d'exécution lorsque vous allez déballer l'Optionnel renvoyé toInt(). Vous devez vérifier que la conversion a réussi avant de forcer le déballage.

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

Éditer:

Si vous êtes sûr que le texte sera un entier, vous pouvez faire quelque chose comme ceci (notez que textsur UITextField est également facultatif)):

if let wageText = Wage.text {
    var wageFloat = Double(wageText.toInt()!)
}
Lance
la source
Eh bien, je n'autorise l'utilisateur à saisir que des chiffres car le clavier est un pavé décimal, de sorte qu'ils ne peuvent pas entrer autre chose que des chiffres.
Stephen Fox
1
wageConversionFloatne sera jamais le float, il plante directement si la chaîne d'entrée est une sorte de float comme 234.56. comment pourrait-elle être une solution acceptée / votée ...?
holex
Cette réponse ne fonctionne pas si le texte contient une valeur décimale. Exemple - cette réponse sera renvoyée 3si le champ de texte a 3.5. En effet, le texte est d'abord converti en un Int, puis le Intest converti en un Float.
rmaddy
1
@StephenFox Gardez à l'esprit qu'un utilisateur peut coller du texte non numérique dans le champ de texte ou que l'utilisateur peut avoir un clavier externe. Ne vous fiez jamais uniquement au clavier pour assurer la saisie des données.
rmaddy
en fait, cela fonctionne, avec des nombres entiers, mais pas avec des décimales. une décimale lancera une erreur fatale!
Miles Works
1

J'ai trouvé un autre moyen de prendre une valeur d'entrée d'un UITextField et de la convertir en flottant:

    var tempString:String?
    var myFloat:Float?

    @IBAction func ButtonWasClicked(_ sender: Any) {
       tempString = myUITextField.text
       myFloat = Float(tempString!)!
    }
Wayne Lampiasi
la source
1

vous pouvez utiliser,

let wg = Float(wage.text!)

Si vous voulez arrondir le flotteur à 2 décimales:

let wg = Float(String(format: "%.2f",wage.text!)
2rahulsk
la source
0

C'est ainsi que je l'ai abordé. Je ne voulais pas "traverser le pont", car il a de toute façon été supprimé de Xcode 6 beta 5, rapide et sale:

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
la source
1
Parce que dans certaines régions du monde, par exemple, une virgule est utilisée à la place d'un décimal. Il est préférable de créer un NSNumberFormatter pour convertir une chaîne en float. Regardez @DmitriFuerle Answer
carmen_munich
@PartiallyFrozenOJ Avez-vous essayé la toDouble()fonction avec la chaîne "10", je veux dire s'il n'y a pas de décimal. Il plantera de toute façon. Parce que dans ce cas, le nombre sera de 1 et vous ne gérez pas cela. Il plantera à else if comps[0] == "" || comps[1] == "". Quoi qu'il en soit, vous êtes si sérieux dans la conversion.
TheTiger
@PartiallyFrozenOJ Mais si la condition était la même en 2014 aussi. En tout cas pas de problème!
TheTiger
0

Par souci d'exhaustivité, il s'agit d'une solution utilisant une extension de UITextField laquelle peut également prendre en compte une locale différente.

Pour 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
la source
En tant que solution générale, cela devrait probablement renvoyer a Float?et ne pas traiter les valeurs invalides comme 0.0. Laissez l'appelant faire quelque chose comme let val = field.floatValue ?? 0.0si un cas donné devait traiter le mauvais résultat comme zéro.
rmaddy
0

Swift 4/5, utilisez juste Float (valeur).

let string_value : String = "123200"

let float_value : Float = Float(string_value)

print(float_value)

Réponse: 123200

Krunal Patel
la source
-1

Utilisez ceci:

 // 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
la source
1
bridgeToObjectiveC () a été supprimé dans la bêta 5
carmen_munich
-4

Moyen facile:

// 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"
}

vous pouvez utiliser la même approche pour d'autres calculs, espérons cette aide !!

Narendar Singh Saini
la source
3
Aussi génial que cela soit, il demandaitfloat
Jack