9

In some languages, like C# for example, you can create a string in the following way:

"String {0} formatted {1} "

And then format it with String.format by passing in the values to format.

The above declaration is good, because you don't have to know of what type its parameters are when you create the string.

I tried to find similar approach in Swift, but what I found out was something like the following format:

"String %d formatted %d"

which requires you to format the string with String(format: , parameters). This is not good because you would also have to know parameter types when declaring the string.

Is there a similar approach in Swift where I wouldn't have to know the parameter types?

0

2 Answers 2

21

Use this one:

let printfOutput = String(format:"%@ %2.2d", "string", 2)

It's the same as printf or the Obj-C formatting.

You can also mix it in this way:

let parm = "string"
let printfOutput = String(format:"\(parm) %2.2d", 2)

Edit: Thanks to MartinR (he knows it all ;-)

Be careful when mixing string interpolation and formatting. String(format:"\(parm) %2.2d", 2) will crash if parm contains a percent character. In (Objective-)C, the clang compiler will warn you if a format string is not a string literal.

This gives some room for hacking:

let format = "%@"
let data = "String"
let s = String(format: "\(format)", data) // prints "String"

In contrast to Obj-C which parses the format string at compile time, Swift does not do that and just interprets it at runtime.

Sign up to request clarification or add additional context in comments.

4 Comments

Though I guess that the preferred Swift way would be to use the \() for such string substitutions. Of course YMMV :-)
Be careful when mixing string interpolation and formatting. String(format:"\(parm) %2.2d", 2) will crash if parm contains a percent character. In (Objective-)C, the clang compiler will warn you if a format string is not a string literal.
Good observation Martin!
@MartinR Thanks. I'll add that info to my answer.
2

In Swift, types need to conform to the CustomStringConvertible protocol in order to be used inside strings. This is also a requirement for the types used in string interpolation like this:

"Integer value \(intVal) and double value \(doubleVal)"

When you understand the CustomStringConvertible, you can create your own function to fulfill your needs. The following function formats the string based on the given arguments and prints it. It uses {} as a placeholder for the argument, but you can change it to anything you want.

func printWithArgs(string: String, argumentPlaceHolder: String = "{}", args: CustomStringConvertible...) {
    var formattedString = string
    
    // Get the index of the first argument placeholder
    var nextPlaceholderIndex = string.range(of: argumentPlaceHolder)
    
    // Index of the next argument to use
    var nextArgIndex = 0

    // Keep replacing the next placeholder as long as there's more placeholders and more unused arguments
    while nextPlaceholderIndex != nil && nextArgIndex < args.count {
        
        // Replace the argument placeholder with the argument
        formattedString = formattedString.replacingOccurrences(of: argumentPlaceHolder, with: args[nextArgIndex].description, options: .caseInsensitive, range: nextPlaceholderIndex)
        
        // Get the next argument placeholder index
        nextPlaceholderIndex = formattedString.range(of: argumentPlaceHolder)
        nextArgIndex += 1
    }
    
    print(formattedString)
}

printWithArgs(string: "First arg: {}, second arg: {}, third arg: {}", args: "foo", 4.12, 100)
// Prints: First arg: foo, second arg: 4.12, third arg: 100

Using a custom implementation allows you to have more control over it and tweak its behavior. For example, if you wanted to, you could modify this code to display the same argument multiple times using placeholders like {1} and {2}, you could fill the arguments in a reversed order, etc.

For more information about string interpolation in Swift: https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID292

5 Comments

I think you misunderstanding my question @alkku, you answer is not what I ask.
this answer should be removed as it is not related to the original question
@der_michael saying it's not related is quite a bold statement. It's not precisely what the OP was asking for, but I'd rather let it remain here as it's suitable in most cases when printing variables. It may be helpful to some (and has been, see upvotes), if one doesn't understand their problem correctly and makes the same misunderstanding I made when I answered the question.
I disagree. If somebody asks you for the nearest gas station you don't start by explaining how a combustion engine works.
@der_michael I updated the answer. I elaborated on how the CustomStringConvertible (was Printable) can be used. It was too vague and required too much imagination earlier, so maybe it is now clearer how this relates to the original question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.