Padding a swift String for printing

Próbuję wydrukować listę łańcuchów wyściełanych na tę samą szerokość.

W C, użyłbym czegoś takiego jak printf("%40s", cstr), Gdzie cstr jest ciągiem C.

W Swift, najlepsze co mogłem wymyślić to:

line += String(format: "%40s",string.cStringUsingEncoding(<someEncoding>))
Czy jest lepszy sposób ?
Author: Vadim Kotov, 2015-09-01

6 answers

Dla Swift > = 3

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

Dla Swift

NSString ma metodę stringByPaddingToLength::

line += string.stringByPaddingToLength(40, withString: " ", startingAtIndex: 0)
 26
Author: Code Different,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-12 23:42:55

W Swift 3 możesz użyć:

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

Result string: "Test string "

Jeśli chcesz wstawić tekst w lewo (Prawy justify), możesz napisać następującą funkcję jako rozszerzenie do 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))
        }
    }
}

Więc jeśli napiszesz:

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

Result string: " Test string"

W Swift 4.1 metoda substring jest przestarzała i istnieje wiele nowych metod do uzyskania podłańcucha. Albo prefix, suffix lub subscripting the String with a Range<String.Index>.

Dla poprzedniego rozszerzenia możemy użyć metody suffix aby osiągnąć ten sam wynik. Ponieważ metoda suffix zwraca String.SubSequence, musi zostać przekonwertowana na String przed zwróceniem.

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))
        }
    }
}
 72
Author: Gustavo Seidler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 03:05:58

Umieść cały string-format-code w extension i użyj go ponownie, gdzie chcesz.

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+++++++"
 7
Author: pacification,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-01 18:39:39
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"

Aby odtworzyć to samo zachowanie co padding(toLength:, withPad:, startingAt:) możemy dodać funkcję rotateTo left do RangeReplaceableCollection

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

I wdrożyć go w następujący sposób:

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"
 6
Author: Leo Dabus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-23 19:01:00

Następujące dwie funkcje zwracają łańcuch wyściełany do podanej szerokości, albo w lewo, albo w prawo. Jest to Pure Swift 4, no NSString, i No C string either. Możesz wybrać, czy ciąg dłuższy niż szerokość wypełnienia będzie obcięty, czy nie.

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)
    }
}
 4
Author: Tom E,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-25 09:47:30

Oto moje rozwiązanie, specyficzne dla String, ale jestem pewien, że ktoś mądrzejszy ode mnie mógłby uczynić je bardziej ogólnym.

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())
    }
}
 0
Author: Zonker.in.Geneva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-11 16:37:56