使用字符串数组格式化字符串

6

我正在尝试创建一个包含字符串数组的字符串,我希望这样做能够成功:

let format = "%@ and %@!"
let str1 = "bla"
let str2 = "blob"

private func formatItNicely(format: String, substrings: [String]) -> String {
    return String(format: format, arguments: substrings)
}

let result = formatItNicely(format, substrings: [str1, str2])

但是我遇到了致命错误:fatal error: can't unsafeBitCast between types of different sizes

我看过这个这个以及这个问题(还有很多其他问题),但我仍然不知道如何完成我想要做的事情。


我会期待这个能够工作,但我不太明白你为什么会有这个期望。一个数组并不等同于可变参数。问题的关键在于Swift没有 "splat" 操作符。你无法将一个数组“转换”为可变参数。 - matt
@matt,我能以不同的方式定义我的函数来实现这个吗?如果我将参数子字符串定义为String...,我会得到相同的结果。 - Daniel
1
你可以手动替换每个字符串中的每个%@,而不使用String(format:)。否则,你将不得不深入了解C变参的东西。 - matt
1
这里有一个很好的讨论: https://www.drivenbycode.com/the-missing-apply-function-in-swift/ - matt
4个回答

7

String(format:, arguments: ) 函数期望第二个参数是一个 [CVarArgType] 类型的值:

let format = "%@ and %@!"
let str1 = "bla"
let str2 = "blob"

private func formatItNicely(format: String, substrings: [CVarArgType]) -> String {
    return String(format: format, arguments: substrings)
}

let result = formatItNicely(format, substrings: [str1, str2])
print(result) // bla and blob!

请注意,如果格式说明符与实际参数不匹配,格式化函数将会崩溃(或给出意外的输出),格式化函数无法检查这一点。


4
当我调用String(format:,arguments:)时,我最终使用了substrings.map { $0 as CVarArgType }。这样子字符串就不必成为CVarArgType - Daniel

3

现在你不必做上面建议的任何事情。

Swift5中,您只需将字符串数组作为参数传递给String.init(format:arguments:)即可。

因此,对我来说,以下内容可以正常工作,无需进行任何类型转换/映射等操作。

let formatString = "First one: %1$@, second one: %2$@"
label.text = String(format: formatString, arguments: ["hello", "blabla"])

2

或者您可以使用可变参数版本:

private func formatItNicely(format: String, _ arguments: CVarArgType...) -> String {
    return String(format: format, arguments: arguments)
}

这样调用:

let format = "%@ and %@!"
let str1 = "bla"
let str2 = "blob"

let result = formatItNicely(format, str1, str2)

1

既然你没有做什么特别有趣的事情,实际上你并不需要内置的格式化字符串逻辑。你可以自己进行替换:

func join(_ arr : [String], withFormatString s: String) -> String {
    var s = s
    for str in arr {
        if let r = s.range(of: "%@") {
            s.replaceSubrange(r, with: str)
        }
    }
    return s
}
let result = join([str1,str2], withFormatString:format)

吹毛求疵:如果arr中的字符串包含%@,则可能会得到错误的结果 :) - Martin R
@MartinR 实际上,我想指出的是,由于他不依赖于内置的字符串格式,因此他可以提供自己极不可能的替换标记。我喜欢使用五个连续的倒置感叹号之类的东西。 - matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接