Swift doble a la cuerda

108

Antes de actualizar xCode 6, no tenía problemas para convertir un doble en una cadena, pero ahora me da un error

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

Me da el mensaje de error "el doble no se puede convertir en una cadena". ¿Hay alguna otra forma de hacerlo?

tim_yng
fuente
5
También puede ser útil definirlo comovar b = "\(a)"
erdekhayser

Respuestas:

211

No es casting, está creando una cadena a partir de un valor con un formato.

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

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

Con un formato diferente:

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

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

También puede omitir la formatpropiedad si no se necesita formato.

zaph
fuente
1
¿Qué tal un doble con un número de dígitos de fracción más grande? Como let a = 2.34934340320 let stringValue = String (formato: "% f", a) dará 2.349343
Nico
1
La pantalla se puede controlar con las opciones de formato de printf, consulte: Especificadores de formato de cadena y printf (3) .
zaph
2
Sólo tienes que cambiar el formato para controlar la cantidad de dígitos: format:"%.1f" = 1 digit // 1.5; format:"%.5f" = 5 digits // 1.50000
Megaetron
3
Actualice su respuesta, en Swift 2.1 solo tiene que hacerlo String(yourDouble).
Alexandre G.
1
Puede usar let en lugar de var. Ahora no es necesario llamarlo varias veces.
Oleksandr
81
let double = 1.5 
let string = double.description

actualizar Xcode 7.1 • Swift 2.1:

Ahora Double también es convertible a String, por lo que simplemente puede usarlo como desee:

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

Swift 3 o posterior podemos extenderlo LosslessStringConvertibley hacerlo genérico

Xcode 11.3 • Swift 5.1 o posterior

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

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

Para un número fijo de dígitos fraccionarios, podemos extender el FloatingPointprotocolo:

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

Si necesita más control sobre el formato de su número (dígitos de fracción mínima y máxima y modo de redondeo) puede usar 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
fuente
1
¿Es esto un truco o es una forma legítima de hacerlo? ¿Causaría algún problema con diferentes versiones de iOS?
Esqarrouth
2
No, no tendrás problemas con las diferentes versiones de iOS. También funciona para OSX. Por cierto, esto es lo que obtienes al hacer una interpolación de cadenas con un Double o un Int.
Leo Dabus
Muy útil. No puede formatear como% f. Y también funciona para Int, por lo que tiene una forma de hacerlo para dos tipos.
Patrik Vaberer
Esto no funcionará para 0.00001, se convierte en "1e-05" como cadena.
Alex
Reemplazar String(format: "%.\(digits)f", self as! CVarArg)conString(format: "%.*f", digits, self as! CVarArg)
rmaddy
21

Además de la respuesta de @Zaph, puede crear extension:

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

Uso:

var a:Double = 1.5
println("output: \(a.toString())")  // output: 1.5
Maxim Shoustin
fuente
1
@MaximShoustin El OP no tiene suficiente representante para votar y responder, se requiere 15. También estoy en desacuerdo con la creación de una extensión, cuando la declaración: a.toString()es vista por otro desarrollador definitivamente habrá un momento WTF.
zaph
1
@Zaph, ¿por qué no? Seguro que puede agregar algún prefijo y cambiarlo myToString()para asegurarse de que su definición personalizada. Pero al igual que en otros lenguajes, la creación de prototipos evita la duplicación de código y un buen mantenimiento.
Maxim Shoustin
Pregunta de novato de @MaximShoustin: ¿cuál es la diferencia entre println("output: \(a.toString())")y println("output: \(a)"). La segunda opción no causa errores de compilación. ¿Es esta opción una mala práctica?
Alex Guerrero
¿Existe una forma inteligente de escribir una extensión de este tipo en Double o FloatingPoint que funcione en un Double opcional para devolver una cadena vacía?
Kinergy
@KinergyyourDouble?.toString() ?? ""
Leo Dabus
11

Swift 3+: prueba estas líneas de código

let num: Double = 1.5

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

para convertir cualquier cosa en una cadena en rápido, excepto tal vez los valores de enumeración, simplemente haga lo que hace en el método println ()

por ejemplo:

var stringOfDBL = "\(myDouble)"
Eric Bob
fuente
3

Swift 4 : use el siguiente código

let number = 2.4
let string = String(format: "%.2f", number)
Abhishek Jain
fuente
1
Es la misma solución que la dada por @ shiv-kumar stackoverflow.com/a/46487485/2227743
Eric Aya
3

Esta función le permitirá especificar el número de posiciones decimales para mostrar:

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

Uso:

let numberString = doubleToStringDecimalPlacesWithDouble(number: x, numberOfDecimalPlaces: 2)
MobileMon
fuente
Reemplazar String(format:"%."+numberOfDecimalPlaces.description+"f", number)conString(format:"%.*f", numberOfDecimalPlaces, number)
rmaddy
3

Aquí hay muchas respuestas que sugieren una variedad de técnicas. Pero al presentar números en la interfaz de usuario, invariablemente desea utilizar un NumberFormatterpara que los resultados estén formateados, redondeados y localizados correctamente:

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 desea un número fijo de decimales, por ejemplo, para valores de moneda

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

Pero la belleza de este enfoque es que estará correctamente localizado, lo que resultará en 10,000.50Estados Unidos pero 10.000,50en Alemania. Las diferentes configuraciones regionales tienen diferentes formatos preferidos para los números, y debemos permitir que NumberFormatterusemos el formato preferido por el usuario final al presentar valores numéricos dentro de la interfaz de usuario.

No hace falta decir que, si bien NumberFormatteres esencial al preparar representaciones de cadenas dentro de la interfaz de usuario, no debe usarse si se escriben valores numéricos como cadenas para almacenamiento persistente, interfaz con servicios web, etc.

Robar
fuente
2
Esto debe marcarse como la respuesta correcta
Asad Khan
2

En Swift 3:

var a: Double = 1.5
var b: String = String(a)
carlson
fuente
1

En Swift 3 es simple como se indica a continuación

let stringDouble =  String(describing: double)
Sebin Roy
fuente
3
Esto vuelve, por ejemplo, "Optional(6.1696108999999995)"para mí.
McSullivan D'Ander
0
var b = String(stringInterpolationSegment: a)

Esto funciona para mi. Puede intentarlo

sevenkplus
fuente
0

En Swift 4, si desea modificar y usar un Double en la interfaz de usuario como una etiqueta de texto "String", puede agregar esto al final de su archivo:

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

}

Y utilícelo así si desea tenerlo en una etiqueta de texto:

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

O imprímalo como un Int:

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

Preferiría el enfoque NSNumber y NumberFormatter (donde sea necesario), también puede usar la extensión para evitar el código hinchado

extension Double {

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

}

U también puede necesitar un enfoque inverso

extension String {

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

}
Giuseppe Mazzilli
fuente
¿Por qué devuelve opcional pero asigna .nan si es nulo? Deberías hacer uno u otro. No ambos. Por cierto, ¿qué hay de malo en usar el inicializador de cadenas? También puede hacerlo más genérico extendiendo el LossLessStringConvertibleprotocolo en lugar de extender Double extension LosslessStringConvertible { var string: String { return .init(self) } }
Leo Dabus
¿Tienes razón regresando Double? Es un rechazo porque ya verifiqué que es nulo y devuelvo NaN
Giuseppe Mazzilli
0

Swift 5 : use el siguiente código

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
fuente
Reemplazar String(format: "%.\(points)f", self)conString(format: "%.*f", points, self)
rmaddy