是否使用Swift格式等效于字符串函数String(format:...)

时间:2015-04-20 13:24:23

标签: string swift

我开始喜欢Swift字符串格式,因为它在字符串中使用变量名,而不是像“%@”那样含糊不清的格式标签

我想从一个包含Swift风格格式的文件中加载一个大字符串(就像这样)

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

然后我想将该String变量的内容提供给一个语句,以免我替换

\(who)

使用运行时的常量/变量的内容。

下面的代码使用字符串常量作为格式化字符串。

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

该代码对我的代码中显示为内联的带引号字符串进行格式化。

相反,我想要类似代码的东西

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

但是我可以在一个常量/变量中传入一个Swift风格的格式字符串,我从文件中读取。

这可能吗?我没有任何运气搜索它,因为我不确定要使用哪些搜索条件。

如果必须的话,我总是可以使用C风格的字符串格式和String类的initWithFormat方法...

4 个答案:

答案 0 :(得分:3)

我认为没有办法做到这一点。字符串插值是通过符合StringInterpolationConvertible协议来实现的,并且可能您希望以与StringLiteralConvertible所需的方法相同的方式进入字符串,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)

不幸的是,你不能用StringInterpolationConvertible做同样的伎俩。了解协议的工作原理可能会有所帮助:

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."

所以,如果您愿意,可以直接自己致电String.init(stringInterpolation:)String.init(stringInterpolationSegment:)(只需尝试String(stringInterpolationSegment: 3.141)String(stringInterpolation: "blah", "blah")),这对您没有多大帮助。你真正需要的是一个Facade函数,它协调对它们的调用。除非在标准库中有一个方便的预先存在的函数,它完全符合我错过的功能,否则我认为你运气不好。我怀疑它是内置于编译器中的。

您可以编写自己的目标,但需要付出很多努力,因为您必须将要手动插入的字符串拆分为位并自行处理,调用段init一个循环。此外,您将遇到调用组合函数的问题,因为您无法将数组splat到可变参数函数调用中。

答案 1 :(得分:1)

我不这么认为。编译器需要能够在编译时解析插值变量。

答案 2 :(得分:0)

我不是Swift程序员,具体而言,但我认为你可以使用Dictionary和标准的字符串替换和拆分方法将它解决为你想要的东西:

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

有了这个,你可以尝试找到“\(”,“读取下一个”和“之前的内容”的出现次数,(this post可以帮助拆分部分,this one,替换部分),在字典中找到它,并从你得到的部分重建你的字符串。

答案 3 :(得分:-2)

这个就像一个魅力:

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