244

I need to create a String with format which can convert Int, Int64, Double, etc types into String. Using Objective-C, I can do it by:

NSString *str = [NSString stringWithFormat:@"%d , %f, %ld, %@", INT_VALUE, FLOAT_VALUE, DOUBLE_VALUE, STRING_VALUE];

How to do same but in Swift?

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
Apurv
  • 17,116
  • 8
  • 51
  • 67

15 Answers15

460

I think this could help you:

import Foundation

let timeNow = time(nil)
let aStr = String(format: "%@%x", "timeNow in hex: ", timeNow)
print(aStr)

Example result:

timeNow in hex: 5cdc9c8d
Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
realityone
  • 13,542
  • 3
  • 13
  • 9
  • 1
    Great answer! This is absolutely the correct way to do it. For others, note that the class method "stringWithFormat" gets converted to a init call on the class with the "WithFormat" turned into a named first argument of "format:". The original question did not add any specific formatting, like changing the number of floating point decimals to display, if he had, yours would be the only answer! – David H Jun 12 '14 at 17:50
  • 4
    Would you link to the documentation? I'm having trouble tracking it down. – dumbledad Nov 13 '15 at 11:25
  • 6
    This method is coming from [`NSString` in `Foundation` framework](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instm/NSString/initWithFormat:). So you have to `import Foundation` to make this to work correctly. Otherwise the expression will call `String.init(T)` , and it will produce something like `"(\"%@%x %x\", 10)"` instead of. – eonil Apr 25 '16 at 04:04
  • 1
    @realityone what do `%@%x` symbols mean? Can you point me to a resource where I can learn more about it. – bibscy Apr 11 '18 at 12:47
  • 8
    @bibscy https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1 – realityone Apr 12 '18 at 03:58
124

nothing special

let str = NSString(format:"%d , %f, %ld, %@", INT_VALUE, FLOAT_VALUE, LONG_VALUE, STRING_VALUE)
kelin
  • 11,323
  • 6
  • 67
  • 104
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
60
let str = "\(INT_VALUE), \(FLOAT_VALUE), \(DOUBLE_VALUE), \(STRING_VALUE)"

Update: I wrote this answer before Swift had String(format:) added to it's API. Use the method given by the top answer.

John Estropia
  • 17,460
  • 4
  • 46
  • 50
  • 6
    I don't think this actually answers the question because there is no formatting. Using this method, you can't format how many decimals to have in your floating points. Using `String(format:arguments:)` would be more appropriate to add formatting – Chris May 26 '15 at 14:30
  • 5
    The OP didn't ask for any formatting, just a way to *create a string with format which can convert int, long, double etc. types into string*. – John Estropia Aug 03 '15 at 13:00
  • The question is unclear then. Because he's comparing what he want's to `-stringWithFormat:` which allows formatting. In Swift, `String(format:arguments:)` would be the Swift version of Obj-C's `-stringWithFormat:` – Chris Aug 04 '15 at 14:12
  • Check the date of the question. This was during Swift's first release when `NSString` methods were not yet implemented in Swift's `String`. – John Estropia Aug 04 '15 at 15:23
  • I stand corrected. Still good to have the newer way visible for anyone searching the same problem in the future – Chris Aug 04 '15 at 15:25
53

No NSString required!

String(format: "Value: %3.2f\tResult: %3.2f", arguments: [2.7, 99.8])

or

String(format:"Value: %3.2f\tResult: %3.2f", 2.7, 99.8)
Yi Jiang
  • 49,435
  • 16
  • 136
  • 136
Durul Dalkanat
  • 7,266
  • 4
  • 35
  • 36
16

I would argue that both

let str = String(format:"%d, %f, %ld", INT_VALUE, FLOAT_VALUE, DOUBLE_VALUE)

and

let str = "\(INT_VALUE), \(FLOAT_VALUE), \(DOUBLE_VALUE)"

are both acceptable since the user asked about formatting and both cases fit what they are asking for:

I need to create a string with format which can convert int, long, double etc. types into string.

Obviously the former allows finer control over the formatting than the latter, but that does not mean the latter is not an acceptable answer.

Lance Clark
  • 446
  • 7
  • 14
  • What about STRING_VALUE: which formatting symbol should be used for Swift strings, is it the same like in the case of NSString-s (which would be %@)? – Igor Vasilev Jan 08 '21 at 12:06
6

First read Official documentation for Swift language.

Answer should be

var str = "\(INT_VALUE) , \(FLOAT_VALUE) , \(DOUBLE_VALUE), \(STRING_VALUE)"
println(str)

Here

1) Any floating point value by default double

EX.
 var myVal = 5.2 // its double by default;

-> If you want to display floating point value then you need to explicitly define such like a

 EX.
     var myVal:Float = 5.2 // now its float value;

This is far more clear.

Dan Loughney
  • 4,647
  • 3
  • 25
  • 40
iPatel
  • 46,010
  • 16
  • 115
  • 137
4
let INT_VALUE=80
let FLOAT_VALUE:Double= 80.9999
let doubleValue=65.0
let DOUBLE_VALUE:Double= 65.56
let STRING_VALUE="Hello"

let str = NSString(format:"%d , %f, %ld, %@", INT_VALUE, FLOAT_VALUE, DOUBLE_VALUE, STRING_VALUE);
 println(str);
neowinston
  • 7,584
  • 10
  • 52
  • 83
3

The accepted answer is definitely the best general solution for this (i.e., just use the String(format:_:) method from Foundation) but...

If you are running Swift ≥ 5, you can leverage the new StringInterpolationProtocol protocol to give yourself some very nice syntax sugar for common string formatting use cases in your app.

Here is how the official documentation summarizes this new protocol:

Represents the contents of a string literal with interpolations while it’s being built up.

Some quick examples:

extension String.StringInterpolation {

    /// Quick formatting for *floating point* values.
    mutating func appendInterpolation(float: Double, decimals: UInt = 2) {
        let floatDescription = String(format: "%.\(decimals)f%", float)
        appendLiteral(floatDescription)
    }

    /// Quick formatting for *hexadecimal* values.
    mutating func appendInterpolation(hex: Int) {
        let hexDescription = String(format: "0x%X", hex)
        appendLiteral(hexDescription)
    }

    /// Quick formatting for *percents*.
    mutating func appendInterpolation(percent: Double, decimals: UInt = 2) {
        let percentDescription = String(format: "%.\(decimals)f%%", percent * 100)
        appendLiteral(percentDescription)
    }

    /// Formats the *elapsed time* since the specified start time.
    mutating func appendInterpolation(timeSince startTime: TimeInterval, decimals: UInt = 2) {
        let elapsedTime = CACurrentMediaTime() - startTime
        let elapsedTimeDescription = String(format: "%.\(decimals)fs", elapsedTime)
        appendLiteral(elapsedTimeDescription)
    }
}

which could be used as:

let number = 1.2345
"Float: \(float: number)" // "Float: 1.23"
"Float: \(float: number, decimals: 1)" // "Float: 1.2"

let integer = 255
"Hex: \(hex: integer)" // "Hex: 0xFF"

let rate = 0.15
"Percent: \(percent: rate)" // "Percent: 15.00%"
"Percent: \(percent: rate, decimals: 0)" // "Percent: 15%"

let startTime = CACurrentMediaTime()
Thread.sleep(forTimeInterval: 2.8)
"∆t was \(timeSince: startTime)" // "∆t was 2.80s"
"∆t was \(timeSince: startTime, decimals: 0)" // "∆t was 3s"

This was introduced by SE-0228, so please be sure to read the original proposal for a deeper understanding of this new feature. Finally, the protocol documentation is helpful as well.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
1

I know a lot's of time has passed since this publish, but I've fallen in a similar situation and create a simples class to simplify my life.

public struct StringMaskFormatter {

    public var pattern              : String    = ""
    public var replecementChar      : Character = "*"
    public var allowNumbers         : Bool      = true
    public var allowText            : Bool      = false


    public init(pattern:String, replecementChar:Character="*", allowNumbers:Bool=true, allowText:Bool=true)
    {
        self.pattern            = pattern
        self.replecementChar    = replecementChar
        self.allowNumbers       = allowNumbers
        self.allowText          = allowText
    }


    private func prepareString(string:String) -> String {

        var charSet : NSCharacterSet!

        if allowText && allowNumbers {
            charSet = NSCharacterSet.alphanumericCharacterSet().invertedSet
        }
        else if allowText {
            charSet = NSCharacterSet.letterCharacterSet().invertedSet
        }
        else if allowNumbers {
            charSet = NSCharacterSet.decimalDigitCharacterSet().invertedSet
        }

        let result = string.componentsSeparatedByCharactersInSet(charSet)
        return result.joinWithSeparator("")
    }

    public func createFormattedStringFrom(text:String) -> String
    {
        var resultString = ""
        if text.characters.count > 0 && pattern.characters.count > 0
        {

            var finalText   = ""
            var stop        = false
            let tempString  = prepareString(text)

            var formatIndex = pattern.startIndex
            var tempIndex   = tempString.startIndex

            while !stop
            {
                let formattingPatternRange = formatIndex ..< formatIndex.advancedBy(1)

                if pattern.substringWithRange(formattingPatternRange) != String(replecementChar) {
                    finalText = finalText.stringByAppendingString(pattern.substringWithRange(formattingPatternRange))
                }
                else if tempString.characters.count > 0 {
                    let pureStringRange = tempIndex ..< tempIndex.advancedBy(1)
                    finalText = finalText.stringByAppendingString(tempString.substringWithRange(pureStringRange))
                    tempIndex = tempIndex.advancedBy(1)
                }

                formatIndex = formatIndex.advancedBy(1)

                if formatIndex >= pattern.endIndex || tempIndex >= tempString.endIndex {
                    stop = true
                }

                resultString = finalText

            }
        }

        return resultString
    }

}

The follow link send to the complete source code: https://gist.github.com/dedeexe/d9a43894081317e7c418b96d1d081b25

This solution was base on this article: http://vojtastavik.com/2015/03/29/real-time-formatting-in-uitextfield-swift-basics/

dede.exe
  • 1,300
  • 1
  • 16
  • 27
1

There is a simple solution I learned with "We <3 Swift" if you can't either import Foundation, use round() and/or does not want a String:

var number = 31.726354765
var intNumber = Int(number * 1000.0)
var roundedNumber = Double(intNumber) / 1000.0

result: 31.726

0

Use this following code:

    let intVal=56
    let floatval:Double=56.897898
    let doubleValue=89.0
    let explicitDaouble:Double=89.56
    let stringValue:"Hello"

    let stringValue="String:\(stringValue) Integer:\(intVal) Float:\(floatval) Double:\(doubleValue) ExplicitDouble:\(explicitDaouble) "
PREMKUMAR
  • 8,283
  • 8
  • 28
  • 51
0

The beauty of String(format:) is that you can save a formatting string and then reuse it later in dozen of places. It also can be localized in this single place. Where as in case of the interpolation approach you must write it again and again.

Igor Vasilev
  • 356
  • 4
  • 6
0

Simple functionality is not included in Swift, expected because it's included in other languages, can often be quickly coded for reuse. Pro tip for programmers to create a bag of tricks file that contains all this reuse code.

So from my bag of tricks we first need string multiplication for use in indentation.

@inlinable func * (string: String, scalar: Int) -> String {
    let array = [String](repeating: string, count: scalar)
    return array.joined(separator: "")
}

and then the code to add commas.

extension Int {
    @inlinable var withCommas:String {
        var i = self
        var retValue:[String] = []
        while i >= 1000 {
            retValue.append(String(format:"%03d",i%1000))
            i /= 1000
        }
        retValue.append("\(i)")
        return retValue.reversed().joined(separator: ",")
    }

    @inlinable func withCommas(_ count:Int = 0) -> String {
        let retValue = self.withCommas
        let indentation = count - retValue.count
        let indent:String = indentation >= 0 ? " " * indentation : ""

        return indent + retValue
    }
}

I just wrote this last function so I could get the columns to line up.

The @inlinable is great because it takes small functions and reduces their functionality so they run faster.

You can use either the variable version or, to get a fixed column, use the function version. Lengths set less than the needed columns will just expand the field.

Now you have something that is pure Swift and does not rely on some old objective C routine for NSString.

Sojourner9
  • 158
  • 11
0

Since String(format: "%s" ...) is crashing at run time, here is code to allow write something like "hello".center(42); "world".alignLeft(42):

extension String {

    // note: symbol names match to nim std/strutils lib:

    func align (_ boxsz: UInt) -> String {
        self.withCString { String(format: "%\(boxsz)s", $0) }
    }

    func alignLeft (_ boxsz: UInt) -> String {
        self.withCString { String(format: "%-\(boxsz)s", $0) }
    }

    func center (_ boxsz: UInt) -> String {
        let n = self.count
        guard boxsz > n else { return self }
        let padding = boxsz - UInt(n)
        let R = padding / 2
        guard R > 0 else { return " " + self }
        let L = (padding%2 == 0) ? R : (R+1)
        return " ".withCString { String(format: "%\(L)s\(self)%\(R)s", $0,$0) }
    }

}
sqr163
  • 1,074
  • 13
  • 24
-3

Success to try it:

 var letters:NSString = "abcdefghijkl"
        var strRendom = NSMutableString.stringWithCapacity(strlength)
        for var i=0; i<strlength; i++ {
            let rndString = Int(arc4random() % 12)
            //let strlk = NSString(format: <#NSString#>, <#CVarArg[]#>)
            let strlk = NSString(format: "%c", letters.characterAtIndex(rndString))
            strRendom.appendString(String(strlk))
        }