填充 swift 字符串以进行打印
Padding a swift String for printing
我正在尝试打印所有填充到相同宽度的字符串列表。
在 C 中,我会使用类似 printf("%40s", cstr),
的东西,其中 cstr 是 C 字符串。
在 Swift 中,我能想到的最好的是:
line += String(format: "%40s",string.cStringUsingEncoding(<someEncoding>))
有没有更好的方法?
对于Swift >= 3
line += string.padding(toLength: 40, withPad: " ", startingAt: 0)
对于 Swift < 3
NSString
有 stringByPaddingToLength:
方法:
line += string.stringByPaddingToLength(40, withString: " ", startingAtIndex: 0)
将所有字符串格式代码放入 extension
并在任何需要的地方重复使用。
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+++++++"
在Swift3中可以使用:
let str = "Test string"
let paddedStr = str.padding(toLength: 20, withPad: " ", startingAt: 0)
结果字符串:"Test string "
如果需要向左填充文本(右对齐),可以编写如下函数作为对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))
}
}
}
所以如果你写:
let str = "Test string"
let paddedStr = str.leftPadding(toLength: 20, withPad: " ")
结果字符串:" Test string"
在 Swift 4.1 中,substring
方法已弃用,有许多新方法可以获取子字符串。 prefix
、suffix
或使用 Range<String.Index>
作为 String
的下标。
对于前面的扩展,我们可以使用suffix
方法来完成相同的结果。由于suffix
方法returns一个String.SubSequence
,返回前需要转成一个String
。
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))
}
}
}
以下两个函数return 将字符串填充到给定的宽度,左对齐或右对齐。它是纯 Swift 4,没有 NSString,也没有 C 字符串。您可以选择是否截断长度超过填充宽度的字符串。
extension String {
func rightJustified(width: Int, truncate: Bool = false) -> String {
guard width > count else {
return truncate ? String(suffix(width)) : self
}
return String(repeating: " ", count: width - count) + self
}
func leftJustified(width: Int, truncate: Bool = false) -> String {
guard width > count else {
return truncate ? String(prefix(width)) : self
}
return self + String(repeating: " ", count: width - count)
}
}
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"
"9.99".dropLast(3).paddingToLeft(upTo: 10, using: "_") // "______9"
要复制与 padding(toLength:, withPad:, startingAt:)
相同的行为,我们可以将 rotateTo left 功能添加到 RangeReplaceableCollection
extension RangeReplaceableCollection {
func rotatingLeft(positions: Int) -> SubSequence {
let index = self.index(startIndex, offsetBy: positions, limitedBy: endIndex) ?? endIndex
return self[index...] + self[..<index]
}
}
并实现如下:
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"
这是我的解决方案,特定于 String
,但我确信有人比我更聪明可以使它更通用。
extension String {
func frontPadding(toLength length: Int, withPad pad: String, startingAt index: Int) -> String {
return String(String(self.reversed()).padding(toLength: length, withPad: pad, startingAt: index).reversed())
}
}
import Foundation // for NSString.padding()
/**
* Custom Extension's API
* ------------------------------
* • str.padEnd(_:_:)
* • str.padStart(_:_:)
* ------------------------------
* • int.padStart(_:_:forceSign:)
*/
extension String {
// str.padEnd(8, "-")
func padEnd(_ length: Int, _ pad: String) -> String {
return padding(toLength: length, withPad: pad, startingAt: 0)
}
// str.padStart(8, "*")
func padStart(_ length: Int, _ pad: String) -> String {
let str = String(self.reversed())
return String(str.padEnd(length, pad).reversed())
}
}
extension Int {
// int.padStart(8)
func padStart(
_ length: Int, // total length
_ pad: String = "0", // pad character
forceSign: Bool = false // force + sign if positive
) -> String {
let isNegative = self < 0
let n = abs(self)
let str = String(n).padStart(length, pad)
return
isNegative ? "- " + str :
forceSign ? "+ " + str :
str
}
}
// test run
let s1 = "abc"
[
s1.padEnd(15, "*"), // abc************
s1.padStart(15, "*"), // ************abc
3.padStart(8, forceSign: true), // + 00000003
(-125).padStart(8) // - 00000125
].forEach{ print([=10=]) }
对于左填充,您可以使用双反转技巧:
String(String(s.reversed()).padding(toLength: 5, withPad: "0", startingAt: 0).reversed())
当然,你可以把它包装成一个扩展:
extension String {
func leftPadding(toLength: Int, withPad: String) -> String {
String(String(reversed()).padding(toLength: toLength, withPad: withPad, startingAt: 0).reversed())
}
}
我正在尝试打印所有填充到相同宽度的字符串列表。
在 C 中,我会使用类似 printf("%40s", cstr),
的东西,其中 cstr 是 C 字符串。
在 Swift 中,我能想到的最好的是:
line += String(format: "%40s",string.cStringUsingEncoding(<someEncoding>))
有没有更好的方法?
对于Swift >= 3
line += string.padding(toLength: 40, withPad: " ", startingAt: 0)
对于 Swift < 3
NSString
有 stringByPaddingToLength:
方法:
line += string.stringByPaddingToLength(40, withString: " ", startingAtIndex: 0)
将所有字符串格式代码放入 extension
并在任何需要的地方重复使用。
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+++++++"
在Swift3中可以使用:
let str = "Test string"
let paddedStr = str.padding(toLength: 20, withPad: " ", startingAt: 0)
结果字符串:"Test string "
如果需要向左填充文本(右对齐),可以编写如下函数作为对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))
}
}
}
所以如果你写:
let str = "Test string"
let paddedStr = str.leftPadding(toLength: 20, withPad: " ")
结果字符串:" Test string"
在 Swift 4.1 中,substring
方法已弃用,有许多新方法可以获取子字符串。 prefix
、suffix
或使用 Range<String.Index>
作为 String
的下标。
对于前面的扩展,我们可以使用suffix
方法来完成相同的结果。由于suffix
方法returns一个String.SubSequence
,返回前需要转成一个String
。
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))
}
}
}
以下两个函数return 将字符串填充到给定的宽度,左对齐或右对齐。它是纯 Swift 4,没有 NSString,也没有 C 字符串。您可以选择是否截断长度超过填充宽度的字符串。
extension String {
func rightJustified(width: Int, truncate: Bool = false) -> String {
guard width > count else {
return truncate ? String(suffix(width)) : self
}
return String(repeating: " ", count: width - count) + self
}
func leftJustified(width: Int, truncate: Bool = false) -> String {
guard width > count else {
return truncate ? String(prefix(width)) : self
}
return self + String(repeating: " ", count: width - count)
}
}
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"
"9.99".dropLast(3).paddingToLeft(upTo: 10, using: "_") // "______9"
要复制与 padding(toLength:, withPad:, startingAt:)
相同的行为,我们可以将 rotateTo left 功能添加到 RangeReplaceableCollection
extension RangeReplaceableCollection {
func rotatingLeft(positions: Int) -> SubSequence {
let index = self.index(startIndex, offsetBy: positions, limitedBy: endIndex) ?? endIndex
return self[index...] + self[..<index]
}
}
并实现如下:
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"
这是我的解决方案,特定于 String
,但我确信有人比我更聪明可以使它更通用。
extension String {
func frontPadding(toLength length: Int, withPad pad: String, startingAt index: Int) -> String {
return String(String(self.reversed()).padding(toLength: length, withPad: pad, startingAt: index).reversed())
}
}
import Foundation // for NSString.padding()
/**
* Custom Extension's API
* ------------------------------
* • str.padEnd(_:_:)
* • str.padStart(_:_:)
* ------------------------------
* • int.padStart(_:_:forceSign:)
*/
extension String {
// str.padEnd(8, "-")
func padEnd(_ length: Int, _ pad: String) -> String {
return padding(toLength: length, withPad: pad, startingAt: 0)
}
// str.padStart(8, "*")
func padStart(_ length: Int, _ pad: String) -> String {
let str = String(self.reversed())
return String(str.padEnd(length, pad).reversed())
}
}
extension Int {
// int.padStart(8)
func padStart(
_ length: Int, // total length
_ pad: String = "0", // pad character
forceSign: Bool = false // force + sign if positive
) -> String {
let isNegative = self < 0
let n = abs(self)
let str = String(n).padStart(length, pad)
return
isNegative ? "- " + str :
forceSign ? "+ " + str :
str
}
}
// test run
let s1 = "abc"
[
s1.padEnd(15, "*"), // abc************
s1.padStart(15, "*"), // ************abc
3.padStart(8, forceSign: true), // + 00000003
(-125).padStart(8) // - 00000125
].forEach{ print([=10=]) }
对于左填充,您可以使用双反转技巧:
String(String(s.reversed()).padding(toLength: 5, withPad: "0", startingAt: 0).reversed())
当然,你可以把它包装成一个扩展:
extension String {
func leftPadding(toLength: Int, withPad: String) -> String {
String(String(reversed()).padding(toLength: toLength, withPad: withPad, startingAt: 0).reversed())
}
}