How to format fixed-length string in swift

For example: var str = String (format: "% 12s -% s", "key", "value")

What I want is a key that will contain characters of length 12. key__________ - value

(underline here is a space)

Thank.

+5
source share
6 answers

Basically, for formatting Stringwith, String(format: _:...)we can use %@:

String(format: "%@ - %@", "key", "value")

But, I believe, the %@width modifier does not support: you cannot %12@or such.

So, you need to convert Stringto COpaquePointerwhich you can format with %s:

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

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

, COpaquePointer C. C , Swift, .

- 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"
+6

Swift 2 COpaquePointer:

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)
+2

:

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

Swift 4

. , %s, Unicode, emojis "ä", "ö", "ü", "ß".

%s Swift:

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

1. arguments: CVarArg...

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

, , .

...

2. Various lines in arguments: CVarArg...

The easiest way to find an extension Stringwith a computed propertyc

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)
    }
}

Using

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)

Your specific problem

Using the second solution:

// 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
source

Swift 5.1 / Xcode 11.1 / iOS 13

This is really the best answer. No C string conversions (spoiled grapheme clusters), no 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
    }
}

Then, to use it, you can do something like this:

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

// Prints "Foobar    Barfoo".
0
source

All Articles