30

I would like to format a string with another string like this:

var str = "Hello, playground"
print (String(format: "greetings %s", str))

This leads to this beautiful result:

greetings 哰૧

I tried with %@ and it works but, as I'm getting format string from another programming language, I would like, if possible to use the %s tag. Is there a way to ?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Julien
  • 846
  • 1
  • 7
  • 19
  • 5
    The `"%s"` format specifier specifies a _C_ string — a null-terminated sequence of bytes. It will also not properly handle non-ASCII/UTF-8 encodings. Can you not search for "%s" in the format string you get and replace it with "%@"? – Itai Ferber Jul 12 '17 at 21:16
  • `%s` expects a C-string, not a Swift string. – rmaddy Jul 12 '17 at 21:16
  • 3
    Why not just use `"greetings \(str)"`? – Peterdk Jul 12 '17 at 21:21
  • If you want CString: https://stackoverflow.com/questions/24103590/how-do-you-convert-a-string-to-a-cstring-in-the-swift-language (there is a Swift 3 answer) – Larme Jul 12 '17 at 22:10
  • 1
    I would avoid the format constructor in String as much as possible. The %s escape isn't made for Objective-C nor Swift strings, it's for C String only. Avoid the %s in the localized text at any cost too... – Dominik Bucher Jul 12 '17 at 22:11
  • 1
    Interesting that the creators of Swift decided %s should NOT work with String. Not sure what benefit that provides? And could it not be overloaded somehow? – William T. Mallard Apr 29 '18 at 17:28

1 Answers1

37

Solution 1: changing the format

If the format is from a reliable external source, you can convert it to replace occurences of %s with %@:

So, instead of:

String(format: "greetings %s", str)

You do:

String(format: "greetings %s".replacingOccurrences(of: "%s", with: "%@"), str)

Solution 2: changing the string

If the format is complex, a simple replacement won't work. For instance:

  • when using a specifier with a numeric character sequence: %1$s
  • when using the '%' character followed by an 's': %%s
  • when using a width modifier: %-10s

In similar cases, we need to stick to a C string.

So instead of:

String(format: "greetings %s", str)

You do:

str.withCString {
    String(format: "greetings %s", $0)
}
Community
  • 1
  • 1
Cœur
  • 37,241
  • 25
  • 195
  • 267