Swift中的精确字符串格式说明符

下面是我以前如何将一个浮点数截断到小数点后两位

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

我查了文档和电子书,但还没找到答案。谢谢!

403955 次浏览

你还不能用字符串插值来做。你最好的选择仍然是NSString格式化:

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

从python中推断,合理的语法可能是:

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

然后允许你使用它们作为:

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

你可以为所有的数字类型定义类似的操作符,不幸的是我还没有找到一种方法来使用泛型。

Swift 5更新

至少在Swift 5中,String直接支持format:初始化式,因此不需要使用NSString,也不再需要@infix属性,这意味着上面的示例应该写成:

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


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


Double.pi % "%5.3f"         // "3.142"

到目前为止,我最好的解决方案,以下来自大卫的反应:

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

我认为这是最类似swift的解决方案,将格式化操作直接绑定到数据类型上。很可能在某个地方有一个内置的格式化操作库,或者它很快就会发布。请记住,该语言仍处于测试阶段。

以下代码:

import Foundation // required for String(format: _, _)


print(String(format: "a float number: %.2f", 1.0321))

将输出:

a float number: 1.03

到目前为止,得到最多投票的答案依赖于NSString方法,并且需要你导入Foundation。

这样做之后,你仍然就可以访问NSLog了。

所以我认为这个问题的答案,如果你在问如何继续在Swift中使用NSLog,很简单:

import Foundation

一个更优雅和通用的解决方案是重写ruby / python %操作符:

// 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]

这里有一个“纯粹的”快速解决方案

 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)")

你仍然可以在Swift中使用NSLog,就像在Objective-C中一样,只是没有@符号。

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

在与Swift合作一段时间后,我想添加这个变化

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

输出:

2014-12-07 21:00:42.128 MyApp[1626:60b] 1.2 1.3 1.4
@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

您也可以用这种方式创建操作符

operator infix <- {}


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


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

我发现String.localizedStringWithFormat工作得很好:

例子:

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


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

这里大多数答案都是有效的。但是,如果要经常格式化数字,可以考虑扩展Float类,添加一个返回格式化字符串的方法。参见下面的示例代码。这一个通过使用数字格式化器和扩展实现了相同的目标。

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))")

控制台显示:

The velocity is 12.33
The velocity is 12.3

SWIFT 3.1更新

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

也用于四舍五入:

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

我不知道两个的小数位数,但这里是如何打印小数位数为零的浮点数,所以我想可以是2位,3位,位…(注意:你必须将CGFloat转换为Double以传递给String(format:),否则它将看到一个0的值)

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))
}

@Christian黛德丽:

而不是:

var k = 1.0
for i in 1...right+1 {
k = 10.0 * k
}
let n = Double(Int(left*k)) / Double(k)
return "\(n)"

也可以是:

let k = pow(10.0, Double(right))
let n = Double(Int(left*k)) / k
return "\(n)"

< em >(更正:) 抱歉混淆* -当然这适用于双打。我认为,最实用的(如果你想让数字四舍五入,而不是被切断)应该是这样的:

infix operator ~> {}
func ~> (left: Double, right: Int) -> Double {
if right <= 0 {
return round(left)
}
let k = pow(10.0, Double(right))
return round(left*k) / k
}
< p > 仅对于Float,只需将Double替换为Float, pow替换为powf, round替换为roundf。 < br > 我发现使用返回类型Double而不是String是最实用的。它的工作原理与字符串输出相同,即:

println("Pi is roughly \(3.1415926 ~> 3)")

打印:Pi大约是3.142
因此,您可以以同样的方式对字符串使用它(您甚至仍然可以编写:println(d ~> 2)),但除此之外,您还可以使用它直接对值进行四舍五入,即:

d = Double(slider.value) ~> 2

或者任何你需要的…

为什么要把它弄得这么复杂?你可以用这个代替:

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

看它在游乐场工作。

PS:解来自:http://rrike.sh/xcode/rounding-various-decimal-places-swift/

使用以下方法

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


println(output)

Swift2示例:iOS设备的屏幕宽度格式化浮点数去除小数

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

Vincent Guerci的ruby / python %操作符,为Swift 2.1更新:

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


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

这是一个非常快简单的的方法,不需要复杂的解决方案。

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

延伸的力量

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)")
< p >输出: 速度是12.3

extension Double {
func formatWithDecimalPlaces(decimalPlaces: Int) -> Double {
let formattedString = NSString(format: "%.\(decimalPlaces)f", self) as String
return Double(formattedString)!
}
}


1.3333.formatWithDecimalPlaces(2)

少打字方式:

func fprint(format: String, _ args: CVarArgType...) {
print(NSString(format: format, arguments: getVaList(args)))
}
import Foundation


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

使用

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

上面有很多不错的答案,但有时模式比“%”更合适。3f“有点官样文章。以下是我在Swift 3中使用NumberFormatter的方法。

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

这里我希望总是显示2个小数,但只有第三个小数不为零时才显示。

//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)

细节

  • Xcode 9.3, Swift 4.1
  • Xcode 10.2.1 (10E1001)

解决方案1

func round () -> Double

(5.2).rounded()
// 5.0
(5.5).rounded()
// 6.0
(-5.2).rounded()
// -5.0
(-5.5).rounded()
// -6.0

func round (_ rule: FloatingPointRoundingRule) -> Double

let x = 6.5


// Equivalent to the C 'round' function:
print(x.rounded(.toNearestOrAwayFromZero))
// Prints "7.0"


// Equivalent to the C 'trunc' function:
print(x.rounded(.towardZero))
// Prints "6.0"


// Equivalent to the C 'ceil' function:
print(x.rounded(.up))
// Prints "7.0"


// Equivalent to the C 'floor' function:
print(x.rounded(.down))
// Prints "6.0"

突变func round()

var x = 5.2
x.round()
// x == 5.0
var y = 5.5
y.round()
// y == 6.0
var z = -5.5
z.round()
// z == -6.0

mutating func round(_ rule: FloatingPointRoundingRule)

// Equivalent to the C 'round' function:
var w = 6.5
w.round(.toNearestOrAwayFromZero)
// w == 7.0


// Equivalent to the C 'trunc' function:
var x = 6.5
x.round(.towardZero)
// x == 6.0


// Equivalent to the C 'ceil' function:
var y = 6.5
y.round(.up)
// y == 7.0


// Equivalent to the C 'floor' function:
var z = 6.5
z.round(.down)
// z == 6.0

解决方案2

extension Numeric {


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


private func toNSNumber() -> NSNumber? {
if let num = self as? NSNumber { return num }
guard let string = self as? String, let double = Double(string) else { return nil }
return NSNumber(value: double)
}


func precision(_ minimumFractionDigits: Int,
roundingMode: NumberFormatter.RoundingMode = NumberFormatter.RoundingMode.halfUp) -> Self? {
guard let number = toNSNumber() else { return nil }
let formatter = NumberFormatter()
formatter.minimumFractionDigits = minimumFractionDigits
formatter.roundingMode = roundingMode
return _precision(number: number, formatter: formatter)
}


func precision(with numberFormatter: NumberFormatter) -> String? {
guard let number = toNSNumber() else { return nil }
return numberFormatter.string(from: number)
}
}

使用

_ = 123.44.precision(2)
_ = 123.44.precision(3, roundingMode: .up)


let numberFormatter = NumberFormatter()
numberFormatter.minimumFractionDigits = 1
numberFormatter.groupingSeparator = " "
let num = 222.3333
_ = num.precision(2)

完整的样品

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


func option2<T: Numeric>(value: T, numberFormatter: NumberFormatter) {
print("Type: \(type(of: value))")
print("Original Value: \(value)")
let value1 = value.precision(with: numberFormatter)
print("formated value = \(value1 != nil ? "\(value1!)" : "nil")\n")
}


func test(with double: Double) {
print("===========================\nTest with: \(double)\n")
let float = Float(double)
let float32 = Float32(double)
let float64 = Float64(double)
let float80 = Float80(double)
let cgfloat = CGFloat(double)


// Exapmle 1
print("-- Option1\n")
option1(value: double)
option1(value: float)
option1(value: float32)
option1(value: float64)
option1(value: float80)
option1(value: cgfloat)


// Exapmle 2


let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 4
numberFormatter.maximumFractionDigits = 9
numberFormatter.usesGroupingSeparator = true
numberFormatter.groupingSeparator = " "
numberFormatter.groupingSize = 3


print("-- Option 2\n")
option2(value: double, numberFormatter: numberFormatter)
option2(value: float, numberFormatter: numberFormatter)
option2(value: float32, numberFormatter: numberFormatter)
option2(value: float64, numberFormatter: numberFormatter)
option2(value: float80, numberFormatter: numberFormatter)
option2(value: cgfloat, numberFormatter: numberFormatter)
}


test(with: 123.22)
test(with: 1234567890987654321.0987654321)

输出

===========================
Test with: 123.22


-- Option1


Type: Double
Original Value: 123.22
value1 = 123.22
value2 = 123.22
value1 + value2 = 246.44


Type: Float
Original Value: 123.22
value1 = nil
value2 = nil


Type: Float
Original Value: 123.22
value1 = nil
value2 = nil


Type: Double
Original Value: 123.22
value1 = 123.22
value2 = 123.22
value1 + value2 = 246.44


Type: Float80
Original Value: 123.21999999999999886
value1 = nil
value2 = nil


Type: CGFloat
Original Value: 123.22
value1 = 123.22
value2 = 123.22
value1 + value2 = 246.44


-- Option 2


Type: Double
Original Value: 123.22
formatted value = 123.2200


Type: Float
Original Value: 123.22
formatted value = 123.220001221


Type: Float
Original Value: 123.22
formatted value = 123.220001221


Type: Double
Original Value: 123.22
formatted value = 123.2200


Type: Float80
Original Value: 123.21999999999999886
formatted value = nil


Type: CGFloat
Original Value: 123.22
formatted value = 123.2200


===========================
Test with: 1.2345678909876544e+18


-- Option1


Type: Double
Original Value: 1.2345678909876544e+18
value1 = 1.23456789098765e+18
value2 = 1.23456789098765e+18
value1 + value2 = 2.4691357819753e+18


Type: Float
Original Value: 1.234568e+18
value1 = nil
value2 = nil


Type: Float
Original Value: 1.234568e+18
value1 = nil
value2 = nil


Type: Double
Original Value: 1.2345678909876544e+18
value1 = 1.23456789098765e+18
value2 = 1.23456789098765e+18
value1 + value2 = 2.4691357819753e+18


Type: Float80
Original Value: 1234567890987654400.0
value1 = nil
value2 = nil


Type: CGFloat
Original Value: 1.2345678909876544e+18
value1 = 1.23456789098765e+18
value2 = 1.23456789098765e+18
value1 + value2 = 2.4691357819753e+18


-- Option 2


Type: Double
Original Value: 1.2345678909876544e+18
formatted value = 1 234 567 890 987 650 000.0000


Type: Float
Original Value: 1.234568e+18
formatted value = 1 234 567 939 550 610 000.0000


Type: Float
Original Value: 1.234568e+18
formatted value = 1 234 567 939 550 610 000.0000


Type: Double
Original Value: 1.2345678909876544e+18
formatted value = 1 234 567 890 987 650 000.0000


Type: Float80
Original Value: 1234567890987654400.0
formatted value = nil


Type: CGFloat
Original Value: 1.2345678909876544e+18
formatted value = 1 234 567 890 987 650 000.0000

使用

CGFloat

Float.roundTo(places:2)

斯威夫特4

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

Swift 4 Xcode 10 Update

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

那么Double和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)"
}
}
}

用法:

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

打印:112 465 848 348 508.46

iOS 15+版本推荐:

2.31234.formatted(.number.precision(.fractionLength(1)))