Is there an equivalent to the string function String (format: ...) using Swift formatting

I'm starting to love Swift's string formatting since it uses variable names in the string rather than ambiguous formatting tags like "% @"

I want to load a large string from a file with Swift style formatting (for example)

Now is the time for all good \(who) to come to babble incoherently.

      

Then I want to pass the content of this String variable to a statement that will not replace

\(who)

      

with the contents of a constant / variable that is at runtime.

Below is the code with string constant as format string.

let who = "programmers"
let aString = "Now is the time for all good \(who) to come to babble incoherently."

      

This code does the formatting of the quoted string that appears in the string in my code.

Instead, I want something like code

let formatString = "Now is the time for all good %@ to come to babble incoherently."
aString = String(format: formatString, who)

      

But where can I pass Swift format string in constant / variable that I read from file.

Is it possible? I had no luck finding it as I didn't know exactly what search terms to use.

I can always use C style string formatting and the initWithFormat method of the String class if I need to ...

+3


source to share


4 answers


I don't think there is a way to do this. String interpolation is implemented through protocol conformance StringInterpolationConvertible

, and presumably you hope to use this in the same way you can use the methods required StringLiteralConvertible

, a la:

let someString = toString(42)

// this is the method String implements to conform to StringLiteralConvertible
let anotherString = String(stringLiteral: someString)

// anotherString will be "42"
print(anotherString)

      

Unfortunately, you cannot do the same trick with StringInterpolationConvertible

. Seeing how the protocol works can help:



struct MyString: Printable {
    let actualString: String
    var description: String { return actualString }
}

extension MyString: StringInterpolationConvertible {
    // first, this will get called for each "segment"
    init<T>(stringInterpolationSegment expr: T) {
        println("Processing segment: " + toString(expr))
        actualString = toString(expr)
    }
    // here is a type-specific override for Int, that coverts
    // small numbers into words:
    init(stringInterpolationSegment expr: Int) {
        if (0..<4).contains(expr) {
            println("Embigening \(expr)")
            let numbers = ["zeo","one","two","three"]
            actualString = numbers[expr]
        }
        else {
            println("Processing segment: " + toString(expr))
            actualString = toString(expr)
        }
    }
    // finally, this gets called with an array of all of the
    // converted segments
    init(stringInterpolation strings: MyString...) {
        // strings will be a bunch of MyString objects
        actualString = "".join(strings.map { $0.actualString })
    }
}

let number = 3
let aString: MyString = "Then shalt thou count to \(number), no more, no less."
println(aString)
// prints "Then shalt thou count to three, no more, no less."

      

So, if you can call String.init(stringInterpolation:)

it String.init(stringInterpolationSegment:)

yourself and yourself (just try String(stringInterpolationSegment: 3.141)

and String(stringInterpolation: "blah", "blah")

) it won't help you much. What you really need is a facade function that coordinates the calls to them. And if there is no convenient pre-existing function in the standard library that does exactly what I missed, I think you're out of luck. I suspect it is built into the compiler.

You can probably write your own to achieve your goal, but put in a lot of effort as you will have to split the string you want to interpolate manually into bits and process it yourself by calling the segment init

in a loop.Also you will run into problems calling the function joins as you cannot split the array into a function variable call.

+3


source


I do not think so. The compiler must be able to resolve the interpolated variable at compile time.



+1


source


I'm not a Swift programmer in particular, but I think you can get around this with something pretty close to what you want using Dictionary and the standard string replacement and splitting methods:

var replacement = [String: String]()
replacement["who"] = "programmers"

      

In this case, you can try to find occurrences of "\ (" by reading what will come next and before ")" ( this post can help with the split part, this one with the replacement part), find it in the dictionary and restore your string from the parts, which you receive.

0


source


this one works like a charm:

let who = "programmers"
let formatString = "Now is the time for all good %@ to come to babble incoherently."
let aString = String(format: formatString, who)

      

-2


source







All Articles