Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Padding a swift String for printing

I'm trying to print a list of Strings all padded to the same width.

In C, I would use something like printf("%40s", cstr), where cstr is a C string.

In Swift, the best I could come up is this:

line += String(format: "%40s",string.cStringUsingEncoding(<someEncoding>))

Is there a better way ?

like image 584
Droopycom Avatar asked Sep 01 '15 18:09

Droopycom


4 Answers

In Swift 3 you can use:

let str = "Test string"
let paddedStr = str.padding(toLength: 20, withPad: " ", startingAt: 0)

Result string: "Test string "

If you need to pad to the left the text (right justify), you can write the following function as an extension to String:

extension String {
    func leftPadding(toLength: Int, withPad character: Character) -> String {
        let newLength = self.characters.count
        if newLength < toLength {
            return String(repeatElement(character, count: toLength - newLength)) + self
        } else {
            return self.substring(from: index(self.startIndex, offsetBy: newLength - toLength))
        }
    }
}

So if you write:

let str = "Test string"
let paddedStr = str.leftPadding(toLength: 20, withPad: " ")

Result string: " Test string"

In Swift 4.1 the substring method is deprecated and there are a number of new methods to obtain a substring. Either prefix, suffix or subscripting the String with a Range<String.Index>.

For the previous extension we can use the suffix method to accomplish the same result. Since the suffix method returns a String.SubSequence, it needs to be converted into a String before being returned.

extension String {
    func leftPadding(toLength: Int, withPad character: Character) -> String {
        let stringLength = self.count
        if stringLength < toLength {
            return String(repeatElement(character, count: toLength - stringLength)) + self
        } else {
            return String(self.suffix(toLength))
        }
    }
}
like image 74
Gustavo Seidler Avatar answered Nov 12 '22 21:11

Gustavo Seidler


For Swift >= 3

line += string.padding(toLength: 40, withPad: " ", startingAt: 0)

For Swift < 3

NSString has the stringByPaddingToLength: method:

line += string.stringByPaddingToLength(40, withString: " ", startingAtIndex: 0)
like image 40
Code Different Avatar answered Nov 12 '22 21:11

Code Different


extension RangeReplaceableCollection where Self: StringProtocol {
    func paddingToLeft(upTo length: Int, using element: Element = " ") -> SubSequence {
        return repeatElement(element, count: Swift.max(0, length-count)) + suffix(Swift.max(count, count-length))
    }
}

"123".paddingToLeft(upTo: 5)              //  "  123"
"123".paddingToLeft(upTo: 5, using: "0")  //  "00123"
"123".paddingToLeft(upTo: 3, using: "0")  //    "123"
"$199.99".dropLast(3).paddingToLeft(upTo: 10, using: "_")  //  "______$199"

To replicate the same behaviour as padding(toLength:, withPad:, startingAt:) we can add rotateTo left functionality to RangeReplaceableCollection

extension RangeReplaceableCollection {
    func rotatingLeft(positions: Int) -> SubSequence {
        let index = self.index(startIndex, offsetBy: positions, limitedBy: endIndex) ?? endIndex
        return self[index...] + self[..<index]
    }
}

And implement it as follow:

extension RangeReplaceableCollection where Self: StringProtocol {
    func paddingToLeft<S: StringProtocol & RangeReplaceableCollection>(upTo length: Int, with string: S, startingAt index: Int = 0) -> SubSequence {
        let string = string.rotatingLeft(positions: index)
        return repeatElement(string, count: length-count/string.count)
            .joined().prefix(length-count) + suffix(Swift.max(count, count-length))
    }
}

"123".paddingToLeft(upTo: 10, with: "abc", startingAt: 2)   //  "cabcabc123"
"123".padding(toLength: 10, withPad: "abc", startingAt: 2)  //  "123cabcabc"
like image 10
Leo Dabus Avatar answered Nov 12 '22 23:11

Leo Dabus


Put all string-format-code into extension and reuse it wherever you want.

extension String {
    func padding(length: Int) -> String {
        return self.stringByPaddingToLength(length, withString: " ", startingAtIndex: 0)
    }

    func padding(length: Int, paddingString: String) -> String {
        return self.stringByPaddingToLength(length, withString: paddingString, startingAtIndex: 0)
    }
}

var str = "str"
print(str.padding(10)) // "str       "
print(str.padding(10, paddingString: "+")) // "str+++++++"
like image 7
pacification Avatar answered Nov 12 '22 22:11

pacification