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 ?
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))
}
}
}
line += string.padding(toLength: 40, withPad: " ", startingAt: 0)
NSString
has the stringByPaddingToLength:
method:
line += string.stringByPaddingToLength(40, withString: " ", startingAtIndex: 0)
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"
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+++++++"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With