web-dev-qa-db-fra.com

Spécificateur de format de chaîne de précision dans Swift

Voici comment j'aurais précédemment tronqué un flottant à deux décimales.

NSLog(@" %.02f %.02f %.02f", r, g, b);

J'ai vérifié la documentation et le livre électronique, mais je n'ai pas réussi à le comprendre. Merci!

351
user3524868

Ma meilleure solution jusqu'ici, suite à la réponse de David :

import Foundation

extension Int {
    func format(f: String) -> String {
        return String(format: "%\(f)d", self)
    }
}

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

let someInt = 4, someIntFormat = "03"
println("The integer number \(someInt) formatted with \"\(someIntFormat)\" looks like \(someInt.format(someIntFormat))")
// The integer number 4 formatted with "03" looks like 004

let someDouble = 3.14159265359, someDoubleFormat = ".3"
println("The floating point number \(someDouble) formatted with \"\(someDoubleFormat)\" looks like \(someDouble.format(someDoubleFormat))")
// The floating point number 3.14159265359 formatted with ".3" looks like 3.142

Je pense que c'est la solution la plus Swift-like, liant les opérations de formatage directement au type de données. Il se peut qu'il existe une bibliothèque intégrée d'opérations de formatage quelque part, ou peut-être sera-t-elle publiée bientôt Gardez à l'esprit que la langue est toujours en version bêta.

253
Anton Tcholakov

un moyen simple est:

print(String(format: "hex string: %X", 123456))
print(String(format: "a float number: %.5f", 1.0321))
720
realityone

J'ai trouvé que String.localizedStringWithFormat fonctionnait très bien:

Exemple:

let value: Float = 0.33333
let unit: String = "mph"

yourUILabel.text = String.localizedStringWithFormat("%.2f %@", value, unit)
122
Valentin

C'est un moyen très rapide et simple qui n'a pas besoin de solution complexe.

let duration = String(format: "%.01f", 3.32323242)
// result = 3.3
70
fatihyildizhan

La plupart des réponses ici sont valables. Toutefois, si vous formatez souvent le nombre, envisagez d'étendre la classe Float pour ajouter une méthode renvoyant une chaîne mise en forme. Voir exemple de code ci-dessous. Celui-ci atteint le même objectif en utilisant un formateur de nombres et une extension.

extension Float {
    func string(fractionDigits:Int) -> String {
        let formatter = NSNumberFormatter()
        formatter.minimumFractionDigits = fractionDigits
        formatter.maximumFractionDigits = fractionDigits
        return formatter.stringFromNumber(self) ?? "\(self)"
    }
}

let myVelocity:Float = 12.32982342034

println("The velocity is \(myVelocity.string(2))")
println("The velocity is \(myVelocity.string(1))")

La console affiche:

The velocity is 12.33
The velocity is 12.3

Swift 3.1 mise à jour

extension Float {
    func string(fractionDigits:Int) -> String {
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = fractionDigits
        formatter.maximumFractionDigits = fractionDigits
        return formatter.string(from: NSNumber(value: self)) ?? "\(self)"
    }
}
55
Donn

Vous ne pouvez pas le faire (encore) avec une interpolation de chaîne. Votre meilleur pari sera toujours le formatage NSString:

println(NSString(format:"%.2f", sqrt(2.0)))

En extrapolant à partir de python, il semble qu'une syntaxe raisonnable pourrait être:

@infix func % (value:Double, format:String) -> String {
    return NSString(format:format, value)
}

Ce qui vous permet ensuite de les utiliser comme:

M_PI % "%5.3f"                // "3.142"

Vous pouvez définir des opérateurs similaires pour tous les types numériques. Malheureusement, je n'ai pas trouvé de moyen de le faire avec des génériques.

31
David Berry
import Foundation

extension CGFloat {
    var string1: String {
        return String(format: "%.1f", self)
    }
    var string2: String {
        return String(format: "%.2f", self)
    }
}

Usage

let offset = CGPoint(1.23, 4.56)
print("offset: \(offset.x.string1) x \(offset.y.string1)")
// offset: 1.2 x 4.6
12
neoneye

Pourquoi le rendre si compliqué? Vous pouvez utiliser ceci à la place:

import UIKit

let PI = 3.14159265359

round( PI ) // 3.0 rounded to the nearest decimal
round( PI * 100 ) / 100 //3.14 rounded to the nearest hundredth
round( PI * 1000 ) / 1000 // 3.142 rounded to the nearest thousandth

Voir le travail dans la cour de récréation.

PS: Solution de: http://rrike.sh/xcode/rounding-various-decimal-places-Swift/

11
Steyn Viljoen

Une solution plus élégante et générique consiste à réécrire Ruby/python % opérateur:

// Updated for beta 5
func %(format:String, args:[CVarArgType]) -> String {
    return NSString(format:format, arguments:getVaList(args))
}

"Hello %@, This is pi : %.2f" % ["World", M_PI]
10
Vincent Guerci

Détails

Xcode 9.3, Swift 4.1

Solution

import Foundation

extension Numeric {

    private func _precision(number: NSNumber, precision: Int, roundingMode: NumberFormatter.RoundingMode) -> Self? {
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = precision
        formatter.roundingMode = roundingMode
        if let formatedNumString = formatter.string(from: number), let formatedNum = formatter.number(from: formatedNumString) {
            return formatedNum as? Self
        }
        return nil

    }

    func precision(_ number: Int, roundingMode: NumberFormatter.RoundingMode = NumberFormatter.RoundingMode.halfUp) -> Self? {

        if let num = self as? NSNumber {
            return _precision(number: num, precision: number, roundingMode: roundingMode)
        }
        if let string = self as? String, let double = Double(string) {
            return _precision(number: NSNumber(value: double), precision: number, roundingMode: roundingMode)
        }
        return nil
    }

}

Usage

import UIKit

func showInfo<T: Numeric>(value: T) {
    print("Type: \(type(of: value))")
    print("Original Value: \(value)")
    let value1 = value.precision(3)
    print("value1 = \(value1 != nil ? "\(value1!)" : "nil")")
    let value2 = value.precision(2)
    print("value2 = \(value2 != nil ? "\(value2!)" : "nil")")
    if let value1 = value1, let value2 = value2 {
        print("value1 + value2 = \(value1 + value2)")
    }
    print("")
}

let double: Double = 232.1987654321
let float = Float(double)
let cgfloat = CGFloat(double)

showInfo(value: double)
showInfo(value: float)
showInfo(value: cgfloat)

Résultat

 enter image description here

6
Vasily Bodnarchuk

Swift 4

let string = String(format: "%.2f", locale: Locale.current, arguments: 15.123)
5
onmyway133

Vous pouvez toujours utiliser NSLog dans Swift comme dans Objective-C sans le signe @.

NSLog("%.02f %.02f %.02f", r, g, b)

Edit: Après avoir travaillé avec Swift depuis un moment, je voudrais aussi ajouter cette variante

    var r=1.2
    var g=1.3
    var b=1.4
    NSLog("\(r) \(g) \(b)")

Sortie:

2014-12-07 21:00:42.128 MyApp[1626:60b] 1.2 1.3 1.4
5
hol
extension Double {
  func formatWithDecimalPlaces(decimalPlaces: Int) -> Double {
     let formattedString = NSString(format: "%.\(decimalPlaces)f", self) as String
     return Double(formattedString)!
     }
 }

 1.3333.formatWithDecimalPlaces(2)
4
Lucas Farah

Les réponses données jusqu'ici qui ont reçu le plus de votes s'appuient sur les méthodes NSString et vont nécessiter l'importation de Foundation.

Cela étant fait, vous avez toujours accès à NSLog.

Je pense donc que la réponse à la question, si vous demandez comment continuer à utiliser NSLog dans Swift, est simplement:

import Foundation

3
fqdn

moins de frappe:

func fprint(format: String, _ args: CVarArgType...) {
    print(NSString(format: format, arguments: getVaList(args)))
}
2
peak
//It will more help, by specify how much decimal Point you want.
let decimalPoint = 2
let floatAmount = 1.10001
let amountValue = String(format: "%0.*f", decimalPoint, floatAmount)
2
Ravi H Malviya

voici une solution "pure" Swift

 var d = 1.234567
operator infix ~> {}
@infix func ~> (left: Double, right: Int) -> String {
    if right == 0 {
        return "\(Int(left))"
    }
    var k = 1.0
    for i in 1..right+1 {
        k = 10.0 * k
    }
    let n = Double(Int(left*k)) / Double(k)
    return "\(n)"
}
println("\(d~>2)")
println("\(d~>1)")
println("\(d~>0)")
2
Christian Dietrich

Pouvoir d'extension

extension Double {
    var asNumber:String {
        if self >= 0 {
            var formatter = NSNumberFormatter()
            formatter.numberStyle = .NoStyle
            formatter.percentSymbol = ""
            formatter.maximumFractionDigits = 1
            return "\(formatter.stringFromNumber(self)!)"
        }
        return ""
    }
}

let velocity:Float = 12.32982342034

println("The velocity is \(velocity.toNumber)")

Sortie: La vitesse est 12.3

2
Muhammad Aamir Ali

Aussi avec arrondi:

extension Float
{
    func format(f: String) -> String
    {
        return NSString(format: "%\(f)f", self)
    }
    mutating func roundTo(f: String)
    {
        self = NSString(format: "%\(f)f", self).floatValue
    }
}

extension Double
{
    func format(f: String) -> String
    {
        return NSString(format: "%\(f)f", self)
    }
    mutating func roundTo(f: String)
    {
        self = NSString(format: "%\(f)f", self).doubleValue
    }
}

x = 0.90695652173913
x.roundTo(".2")
println(x) //0.91
1
ChikabuZ

Une version de l'opérateur Ruby/python% de Vincent Guerci, mise à jour pour Swift 2.1:

func %(format:String, args:[CVarArgType]) -> String {
  return String(format:format, arguments:args)
}

"Hello %@, This is pi : %.2f" % ["World", M_PI]
1
paul king

utiliser la méthode ci-dessous

let output = String.localizedStringWithFormat(" %.02f %.02f %.02f", r, g, b)

println(output)
1
Ramkumar chintala

Vous pouvez également créer un opérateur de cette manière 

operator infix <- {}

func <- (format: String, args:[CVarArg]) -> String {
    return String(format: format, arguments: args)
}

let str = "%d %.1f" <- [1453, 1.123]
1
otello

Beaucoup de bonnes réponses ci-dessus, mais parfois un motif est plus approprié que la sorte de "gobbledygook". Voici ma prise en utilisant un NumberFormatter dans Swift 3.

extension Double {
  func format(_ pattern: String) -> String {
    let formatter = NumberFormatter()
    formatter.format = pattern
    return formatter.string(from: NSNumber(value: self))!
  }    
}

let n1 = 0.350, n2 = 0.355
print(n1.format("0.00#")) // 0.35
print(n2.format("0.00#")) // 0.355

Ici, je voulais que 2 décimales soient toujours affichées, mais la troisième seulement si ce n’était pas zéro.

1
AlexT

Exemple Swift2: largeur d'écran du périphérique iOS formatant le flottant en supprimant la décimale

print(NSString(format: "Screen width = %.0f pixels", CGRectGetWidth(self.view.frame)))

Je ne sais pas à propos de deux décimales, mais voici comment vous pouvez imprimer des flottants avec zéro décimale. J'imagine donc que vous pouvez avoir 2, 3, places ... (Remarque: vous devez convertit CGFloat en double pour passer en chaîne (format :) ou il verra une valeur de zéro)

func logRect(r: CGRect, _ title: String = "") {
    println(String(format: "[ (%.0f, %.0f), (%.0f, %.0f) ] %@",
        Double(r.Origin.x), Double(r.Origin.y), Double(r.size.width), Double(r.size.height), title))
}
0
clearlight

Qu'en est-il des extensions sur les types Double et CGFloat: 

extension Double {

   func formatted(_ decimalPlaces: Int?) -> String {
      let theDecimalPlaces : Int
      if decimalPlaces != nil {
         theDecimalPlaces = decimalPlaces!
      }
      else {
         theDecimalPlaces = 2
      }
      let theNumberFormatter = NumberFormatter()
      theNumberFormatter.formatterBehavior = .behavior10_4
      theNumberFormatter.minimumIntegerDigits = 1
      theNumberFormatter.minimumFractionDigits = 1
      theNumberFormatter.maximumFractionDigits = theDecimalPlaces
      theNumberFormatter.usesGroupingSeparator = true
      theNumberFormatter.groupingSeparator = " "
      theNumberFormatter.groupingSize = 3

      if let theResult = theNumberFormatter.string(from: NSNumber(value:self)) {
         return theResult
      }
      else {
         return "\(self)"
      }
   }
}

Usage: 

let aNumber: Double = 112465848348508.458758344
Swift.print("The number: \(aNumber.formatted(2))")

impressions: 112 465 848 348 508.46

0
M Wilm

Swift 4 Mise à jour Xcode 10

extension Double {
    var asNumber:String {
        if self >= 0 {
            let formatter = NumberFormatter()
            formatter.numberStyle = .none
            formatter.percentSymbol = ""
            formatter.maximumFractionDigits = 2
            return "\(formatter.string(from: NSNumber(value: self)) ?? "")"
        }
        return ""
    }
}
0
Leanid Vouk
@infix func ^(left:Double, right: Int) -> NSNumber {
    let nf = NSNumberFormatter()
    nf.maximumSignificantDigits = Int(right)
    return  nf.numberFromString(nf.stringFromNumber(left))
}


let r = 0.52264
let g = 0.22643
let b = 0.94837

println("this is a color: \(r^3) \(g^3) \(b^3)")

// this is a color: 0.523 0.226 0.948
0
user3778351