Swift double en chaîne

108

Avant de mettre à jour xCode 6, je n'avais aucun problème à convertir un double en chaîne mais maintenant cela me donne une erreur

var a: Double = 1.5
var b: String = String(a)

Cela me donne le message d'erreur "le double n'est pas convertible en chaîne". Y a-t-il un autre moyen de le faire?

tim_yng
la source
5
Il peut également être utile de simplement le définir commevar b = "\(a)"
erdekhayser

Réponses:

211

Il ne s'agit pas de cast, il crée une chaîne à partir d'une valeur avec un format.

let a: Double = 1.5
let b: String = String(format: "%f", a)

print("b: \(b)") // b: 1.500000

Avec un format différent:

let c: String = String(format: "%.1f", a)

print("c: \(c)") // c: 1.5

Vous pouvez également omettre la formatpropriété si aucune mise en forme n'est nécessaire.

zaph
la source
1
Qu'en est-il d'un double avec un plus grand nombre de chiffres de fraction? Comme let a = 2.34934340320 let stringValue = String (format: "% f", a) donnera 2.349343
Nico
1
L'affichage peut être contrôlé avec les options de formatage printf, voir: Spécificateurs de format de chaîne et printf (3) .
zaph
2
Vous avez juste à changer le format pour contrôler la quantité de chiffres: format:"%.1f" = 1 digit // 1.5; format:"%.5f" = 5 digits // 1.50000
Megaetron
3
Veuillez mettre à jour votre réponse, dans Swift 2.1, il vous suffit de le faire String(yourDouble).
Alexandre G.24
1
Vous pouvez utiliser let au lieu de var. Il n'est pas nécessaire maintenant de l'appeler plusieurs fois.
Oleksandr
81
let double = 1.5 
let string = double.description

mettre à jour Xcode 7.1 • Swift 2.1:

Maintenant, Double est également convertible en String, vous pouvez donc simplement l'utiliser comme vous le souhaitez:

let double = 1.5
let doubleString = String(double)   // "1.5"

Swift 3 ou version ultérieure, nous pouvons l'étendre LosslessStringConvertibleet le rendre générique

Xcode 11.3 • Swift 5.1 ou version ultérieure

extension LosslessStringConvertible { 
    var string: String { .init(self) } 
}

let double = 1.5 
let string = double.string  //  "1.5"

Pour un nombre fixe de chiffres de fraction, nous pouvons étendre le FloatingPointprotocole:

extension FloatingPoint {
    func fixedFraction(digits: Int) -> String {
        return String(format: "%.*f", digits, self as! CVarArg)
    }
}

Si vous avez besoin de plus de contrôle sur votre format de nombre (chiffres de fraction minimum et maximum et mode d'arrondi), vous pouvez utiliser NumberFormatter:

extension Formatter {
    static let number = NumberFormatter()
}

extension FloatingPoint {
    func fractionDigits(min: Int = 2, max: Int = 2, roundingMode: NumberFormatter.RoundingMode = .halfEven) -> String {
        Formatter.number.minimumFractionDigits = min
        Formatter.number.maximumFractionDigits = max
        Formatter.number.roundingMode = roundingMode
        Formatter.number.numberStyle = .decimal
        return Formatter.number.string(for: self) ?? ""
    }
}

2.12345.fractionDigits()                                    // "2.12"
2.12345.fractionDigits(min: 3, max: 3, roundingMode: .up)   // "2.124"
Leo Dabus
la source
1
est-ce un hack ou est-ce une façon légitime de le faire? cela causerait-il des problèmes avec différentes versions d'ios?
Esqarrouth
2
Non, vous n'aurez aucun problème avec les différentes versions d'ios. Cela fonctionne également pour OSX. BTW c'est ce que vous obtenez lorsque vous effectuez une interpolation de chaîne avec un double ou un int.
Leo Dabus
Très utile. Vous ne pouvez pas formater comme% f. Et cela fonctionne également pour Int, vous avez donc une façon de le faire pour deux types.
Patrik Vaberer
Cela ne fonctionnera pas pour 0,00001, il devient "1e-05" sous forme de chaîne.
Alex
Remplacer String(format: "%.\(digits)f", self as! CVarArg)parString(format: "%.*f", digits, self as! CVarArg)
rmaddy
21

En plus de @Zaph answer, vous pouvez créer extension:

extension Double {
    func toString() -> String {
        return String(format: "%.1f",self)
    }
}

Usage:

var a:Double = 1.5
println("output: \(a.toString())")  // output: 1.5
Maxim Shoustin
la source
1
@MaximShoustin L'OP n'a pas assez de représentants pour voter et répondre, 15 est requis. Je suis également en désaccord avec la création d'une extension, lorsque la déclaration: a.toString()est vue par un autre développeur, il y aura certainement un moment WTF.
zaph
1
@Zaph pourquoi pas. Bien sûr, vous pouvez ajouter un préfixe et le changer myToString()pour être sûr que sa définition personnalisée. Mais comme dans d'autres langages, le prototypage permet d'éviter la duplication de code et une bonne maintenance.
Maxim Shoustin
@MaximShoustin question pour les débutants: quelle est la différence entre println("output: \(a.toString())")et println("output: \(a)"). La deuxième option ne provoque pas d'erreurs de compilation. Cette option est-elle une mauvaise pratique?
Alex Guerrero
Existe-t-il un moyen intelligent d'écrire une telle extension sur Double ou FloatingPoint qui fonctionnerait sur un Double facultatif pour renvoyer une chaîne vide?
Kinergy
@KinergyyourDouble?.toString() ?? ""
Leo Dabus
11

Swift 3+: essayez ces lignes de code

let num: Double = 1.5

let str = String(format: "%.2f", num)
Shiv Kumar
la source
9

pour faire quoi que ce soit une chaîne en swift sauf peut-être les valeurs enum faites simplement ce que vous faites dans la méthode println ()

par exemple:

var stringOfDBL = "\(myDouble)"
Eric Bob
la source
3

Swift 4 : utilisez le code suivant

let number = 2.4
let string = String(format: "%.2f", number)
Abhishek Jain
la source
1
C'est la même solution que celle donnée par @ shiv-kumar stackoverflow.com/a/46487485/2227743
Eric Aya
3

Cette fonction vous permettra de spécifier le nombre de décimales à afficher:

func doubleToString(number:Double, numberOfDecimalPlaces:Int) -> String {
    return String(format:"%."+numberOfDecimalPlaces.description+"f", number)
}

Usage:

let numberString = doubleToStringDecimalPlacesWithDouble(number: x, numberOfDecimalPlaces: 2)
MobileMon
la source
Remplacer String(format:"%."+numberOfDecimalPlaces.description+"f", number)parString(format:"%.*f", numberOfDecimalPlaces, number)
rmaddy
3

Il y a de nombreuses réponses ici qui suggèrent une variété de techniques. Mais lorsque vous présentez des nombres dans l'interface utilisateur, vous souhaitez invariablement utiliser a NumberFormatterpour que les résultats soient correctement formatés, arrondis et localisés:

let value = 10000.5

let formatter = NumberFormatter()
formatter.numberStyle = .decimal

guard let string = formatter.string(for: value) else { return }
print(string) // 10,000.5

Si vous voulez un nombre fixe de décimales, par exemple pour les valeurs monétaires

let value = 10000.5

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2

guard let string = formatter.string(for: value) else { return }
print(string) // 10,000.50

Mais la beauté de cette approche, c'est qu'elle sera correctement localisée, aboutissant 10,000.50aux États-Unis mais 10.000,50en Allemagne. Différents paramètres régionaux ont différents formats préférés pour les nombres, et nous devrions laisser NumberFormatterutiliser le format préféré par l'utilisateur final lors de la présentation de valeurs numériques dans l'interface utilisateur.

Il va sans dire que bien que ce NumberFormattersoit essentiel lors de la préparation de représentations sous forme de chaîne dans l'interface utilisateur, il ne doit pas être utilisé si vous écrivez des valeurs numériques sous forme de chaînes pour un stockage persistant, une interface avec des services Web, etc.

Rob
la source
2
Cela devrait être marqué comme la bonne réponse
Asad Khan
2

Dans Swift 3:

var a: Double = 1.5
var b: String = String(a)
Carlson
la source
1

Dans swift 3, c'est simple comme indiqué ci-dessous

let stringDouble =  String(describing: double)
Sebin Roy
la source
3
Cela revient par exemple "Optional(6.1696108999999995)"pour moi.
McSullivan D'Ander
0
var b = String(stringInterpolationSegment: a)

Cela fonctionne pour moi. Vous pouvez avoir un essai

Sevenkplus
la source
0

Dans Swift 4, si vous souhaitez modifier et utiliser un Double dans l'interface utilisateur en tant que textLabel "String", vous pouvez l'ajouter à la fin de votre fichier:

    extension Double {
func roundToInt() -> Int{
    return Int(Darwin.round(self))
}

}

Et utilisez-le comme ceci si vous aimez l'avoir dans un texte:

currentTemp.text = "\(weatherData.tempCelsius.roundToInt())"

Ou imprimez-le comme un Int:

print(weatherData.tempCelsius.roundToInt())
Patrik Rikama-Hinnenberg
la source
0

Je préférerais l'approche NSNumber et NumberFormatter (le cas échéant), vous pouvez également utiliser l'extension pour éviter le code de ballonnement

extension Double {

   var toString: String {
      return NSNumber(value: self).stringValue
   }

}

U peut également avoir besoin d'une approche inversée

extension String {

    var toDouble: Double {
        return Double(self) ?? .nan
    }

}
Giuseppe Mazzilli
la source
pourquoi renvoyez-vous facultatif mais attribuez-vous .nan si nul? Vous devriez faire l'un ou l'autre. Pas les deux. Btw Quel est le problème avec l'utilisation de l'initialiseur String? Vous pouvez également rendre le LossLessStringConvertibleprotocole d'extension plus générique au lieu d'étendre Double extension LosslessStringConvertible { var string: String { return .init(self) } }
Leo Dabus
Vous avez raison de revenir Double? Est un refus puisque je vérifie déjà qu'il est nul et je retourne NaN
Giuseppe Mazzilli
0

Swift 5 : utilisez le code suivant

extension Double {

    func getStringValue(withFloatingPoints points: Int = 0) -> String {
        let valDouble = modf(self)
        let fractionalVal = (valDouble.1)
        if fractionalVal > 0 {
            return String(format: "%.*f", points, self)
        }
        return String(format: "%.0f", self)
    }
}
g212gs
la source
Remplacer String(format: "%.\(points)f", self)parString(format: "%.*f", points, self)
rmaddy