如何在Swift中使用固定长度格式化字符串

9
例如: var str = String(format: "%12s - %s", "key", "value")
我想要的是key将保持长度为12个字符。 key__________ - value (这里的下划线是空格)
谢谢。
6个回答

10
根据文档,COpaquePointer 是一个不透明的 C 指针的包装器。不透明指针用于表示不能在 Swift 中表示的类型的 C 指针,例如不完整的结构体类型。
键是一个 String - 原生的 Swift 类型。我相信最好使用这个 Swift String 函数:
let testString = "bla bli blah"
testString.stringByPaddingToLength(3, withString: " ", startingAtIndex: 0) 
//output = "bla"

Swift 3

let testString = "bla bli blah"
testString.padding(toLength: 3, withPad: " ", startingAt: 0) 
//output = "bla"

4
基本上,使用String(format: _:...)格式化String,我们可以使用%@
String(format: "%@ - %@", "key", "value")

但是,我相信%@不支持 "width" 修饰符:你不能像这样使用 %12@

因此,您必须将String转换为COpaquePointer,然后可以使用%s格式化:

var key = "key"
var val = "value"

var str = String(format: "%-12s - %s",
    COpaquePointer(key.cStringUsingEncoding(NSUTF8StringEncoding)!),
    COpaquePointer(val.cStringUsingEncoding(NSUTF8StringEncoding)!)
)
// -> "key          - value"

3

Swift 5.1 / Xcode 11.1 / iOS 13

这确实是最佳答案。没有 C 字符串转换(破坏字形簇),没有 UnsafeBufferPointer

public extension String {
    func paddedToWidth(_ width: Int) -> String {
        let length = self.count
        guard length < width else {
            return self
        }

        let spaces = Array<Character>.init(repeating: " ", count: width - length)
        return self + spaces
    }
}

然后,要使用它,您可以这样做:

let fubar = "Foobar".paddedToWidth(10) + "Barfoo"
print(fubar)

// Prints "Foobar    Barfoo".

2

不使用COpaquePointer的Swift 2版本:

import Foundation
let str = "hi".nulTerminatedUTF8
let padded = str.withUnsafeBufferPointer() {
    return String(format: "%-12s", $0.baseAddress!)
}

print(padded)

Swift 3:

import Foundation
let str = "hi".utf8CString
let padded = str.withUnsafeBufferPointer() {
    return String(format: "%-12s", $0.baseAddress!)
}

print(padded)

0

Swift 4 更新

注意:使用%s格式化的字符串无法正确表示像表情符号和“ä”、“ö”、“ü”、“ß”这样的Unicode字符。

有两种简单的方法可以解决Swift代码中%s一般问题

接口:String(format: String, arguments: CVarArg...)

1. 如果在arguments: CVarArg...中只有一个字符串

let stringToFormat = "test"
let formattedString = stringToFormat.withCString{
    String(format: "%s", $0)
}

如果您需要使用多个字符串,这将变得非常繁琐,您必须使用嵌套闭包。因此...
2.在arguments: CVarArg...中使用不同的字符串。
最简单的方法是创建一个扩展至String的计算属性c
extension String {
    // nested `struct` which is needed
    // to keep the `baseAdress` pointer valid (see (*))
    struct CString: CVarArg {
        // needed to conform to `CVarArg`
        var _cVarArgEncoding: [Int] = []

        // needed to keep the `baseAdress` pointer valid (see (*))
        var cstring: ContiguousArray<CChar> = []
        
        init(string: String) {
            // is essentially just a (special) `Array`
            cstring = string.utf8CString
            
            self._cVarArgEncoding = cstring.withUnsafeBufferPointer{ 
                // use the `_cVarArgEncoding` of the first Buffer address (*)
                $0.baseAddress!._cVarArgEncoding
            }
        }
    }
    
    // you only need to use this property (`c` stands for `CString`)
    // e.g.: String(format: "%s", "test".c)
    var c: CString {
        return CString(string: self)
    }
}

用法

let stringToFormat1 = "test1"
let stringToFormat2 = "test2"
// note the `.c` at the end of each variable/literal
let formattedString = String(format: "%s %s %s", stringToFormat1.c, stringToFormat2.c, "test3".c)

您的具体问题

使用第二种解决方案:

// note: it should be `-12` instead of `12` in order to pad the string to the right
var str = String(format: "%-12s - %s", "key".c, "value".c)

0

首先构建一个格式化字符串:

let formatString = String(format: "%%%ds", key)  // gives "%12s" if key is 12
let str = String(format: formatString, value)

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