How to Use Println in Swift to Format Number

How to use println in Swift to format number

Here's the shortest solution I found thus far:

let avgTemp = 66.844322156
println(NSString(format:"%.2f", avgTemp))

Its like the swift version of NSString's stringWithFormat

Precision String Format Specifier In Swift

My best solution so far, following from David's response:

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

I think this is the most Swift-like solution, tying the formatting operations directly to the data type. It may well be that there is a built-in library of formatting operations somewhere, or maybe it will be released soon. Keep in mind that the language is still in beta.

Swift number formatting

You can construct a string with a c-like formatting using this constructor:

String(format: String, arguments:[CVarArgType])

Sample usage:

var x = 10

println(String(format: "%04d", arguments: [x])) // This will print "0010"

If you're going to use it a lot, and want a more compact form, you can implement an extension like this:

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

allowing to simplify its usage as in this example:

"%d apples cost $%03.2f".format([4, 4 * 0.33])

String formatting of a Double

There's no way to do this using String interpolation.

You can find a good discussion about this on this Apple Dev Forum post.

You can use NSNumberFormatter or NSDateFormatter to format the output.

Alternatively, to use printf-like syntax, you can still use NSString:

var str = NSString(format: "Hello, world %.2f", 42.12312312313)

Format println output in a table

I found a quick and easy way to generate columnar text output in Swift (3.0) using the String method "padding(::)" [In Swift 2.x, the method is named "stringByPaddingToLength(::)"]. It allows you to specify the width of your column, the text you want to use as a pad, and the index of the pad to start with. Works like a charm if you don't mind that it only works with left-aligned text columns. If you want other alignments, you have to buy into the other methods of character counting and other such complexities.

The solution below is contrived to illustrate the utility of the method "padding(::)". Obviously, the best way to leverage this would be to create a function that iterated through a collection to produce the desired table while minimizing code repetition. I did it this way to focus on the task at hand.

Lastly, "println" doesn't seem to exist in Swift 2.x+, so I reverted to "print()".

To illustrate an example using your stated problem:

//Set up the data
let n : Int = 5
let result1 = 1000.0
let result2 = 20000.0
let time1 = "1000ms"
let time2 = "1250ms"

//Establish column widths
let column1PadLength = 8
let columnDefaultPadLength = 12

//Define the header string
let headerString = "n".padding(toLength: column1PadLength, withPad: " ", startingAt: 0) + "result1".padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0) + "result2".padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0) + "time1".padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0) + "time2".padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0)

//Define the line separator
let lineString = "".padding(toLength: headerString.characters.count, withPad: "-", startingAt: 0)

//Define the string to display a line of our data
let nString = String(n)
let result1String = String(result1)
let result2String = String(result2)
let dataString = nString.padding(toLength: column1PadLength, withPad: " ", startingAt: 0) + result1String.padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0) + result2String.padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0) + time1.padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0) + time2.padding(toLength: columnDefaultPadLength, withPad: " ", startingAt: 0)

//Print out the data table
print("\(headerString)\n\(lineString)\n\(dataString)")

The output will be printed to your console in a tidy columnar format:

n       result1     result2     time1       time2       
--------------------------------------------------------
5 1000.0 20000.0 1000ms 1250ms

Changing the variable "columnDefaultPadLength" from 12 to 8 will result in the following output:

n       result1 result2 time1   time2   
----------------------------------------
5 1000.0 20000.0 1000ms 1250ms

Finally, reducing the padding length to a value less than the data truncates the data instead of generating errors, very handy! Changing the "columnDefaultPadLength" from 8 to 4 results in this output:

n       resuresutimetime
------------------------
5 1000200010001250

Obviously not a desired format, but with the simple adjustment of the padding length, you can quickly tweak the table into a compact yet readable form.

How to print formatted Decimal value in Swift?

Decimal is bridged with NSDecimalNumber, which is a subclass of NSNumber so NSNumberFormatter can handle it

let decimal = Decimal(11.24)
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
let string = formatter.string(from: decimal as NSDecimalNumber)!

Swift Print function formatting

Yes, it is similar to ${} in javaScript, and it is called String Interpolation:

String interpolation is a way to construct a new String value from a mix of constants, variables, literals, and expressions by including their values inside a string literal.

You can find more detailed information in here: Swift Documentation
under the section "String Interpolation".

Swift 4: Formatting number's into friendly K's

This answer formats by truncating (versus rounding). 1,515 rounded would generate 2k whereas truncated would generate 1.5k. The function requires reducing a number's scale (removing digits to the right of the decimal) which I've just packaged as an extension so it can be used anywhere (not just in the function).

extension Double {
func reduceScale(to places: Int) -> Double {
let multiplier = pow(10, Double(places))
let newDecimal = multiplier * self // move the decimal right
let truncated = Double(Int(newDecimal)) // drop the fraction
let originalDecimal = truncated / multiplier // move the decimal back
return originalDecimal
}
}

func formatNumber(_ n: Int) -> String {
let num = abs(Double(n))
let sign = (n < 0) ? "-" : ""

switch num {
case 1_000_000_000...:
var formatted = num / 1_000_000_000
formatted = formatted.reduceScale(to: 1)
return "\(sign)\(formatted)B"

case 1_000_000...:
var formatted = num / 1_000_000
formatted = formatted.reduceScale(to: 1)
return "\(sign)\(formatted)M"

case 1_000...:
var formatted = num / 1_000
formatted = formatted.reduceScale(to: 1)
return "\(sign)\(formatted)K"

case 0...:
return "\(n)"

default:
return "\(sign)\(n)"
}
}

You can fine tune this method for specific cases, such as returning 100k instead of 100.5k or 1M instead of 1.1M. This method handles negatives as well.

print(formatNumber(1515)) // 1.5K
print(formatNumber(999999)) // 999.9K
print(formatNumber(1000999)) // 1.0M

Swift: format console-log

First, for the time, you can get the current hour and minute as String:

func printTime()->String{
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let hour = components.hour
let minutes = components.minute

return "\(hour):\(minutes)"
}

And for the function etc. you can use the Swift Literal Expressions __FILE__, __FUNCTION__ and __LINE__.

But you don't want to set it each time you want to log. So you could do something like that:

func prettyPrint(print: String, file:String = __FILE__, functionName: String = __FUNCTION__, line:Int = __LINE__) {
println("\(printTime()) \(file) > \(functionName) [line \(line)] \(print)")

}

You call prettyPrint like that:

prettyPrint("hey")

And you will get the following output:

/Path/To/Your/File/MyClass.swift > hello [line 81] hey

But as you only want the name of your class, you can remove the path with the following function:

func getFile(path:String = __FILE__)->String{
var parts = path.componentsSeparatedByString("/")
return parts[parts.count-1]
}

Or, as ChikabuZ mentioned in his answer you can directly check the class:

let className = NSStringFromClass(self.classForCoder).pathExtension

Final Function

And here the final function(s):

func getFile(path:String = __FILE__)->String{
var parts = path.componentsSeparatedByString("/")
return parts[parts.count-1]
}
func prettyPrint(print: String, functionName: String = __FUNCTION__, line:Int = __LINE__) {
println("\(printTime()) \(getFile()) > \(functionName) [line \(line)] \(print)")

}

func printTime()->String{
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let hour = components.hour
let minutes = components.minute

return "\(hour):\(minutes)"
}

And the result will be:

MyClass.swift > hello [line 81] hey

You should also note @emaloney's answer to this question. Specifically that

println()-based solutions result in output being captured by the Apple System Log (ASL).

Ideally switch to NSLog or a full blown logging system



Related Topics



Leave a reply



Submit