File: StringExtensions.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (140 lines) | stat: -rw-r--r-- 4,083 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 This source file is part of the Swift.org open source project

 Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
 Licensed under Apache License v2.0 with Runtime Library Exception

 See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Foundation


extension String {
    /**
     Remove trailing newline characters. By default chomp removes
     all trailing \n (UNIX) or all trailing \r\n (Windows) (it will
     not remove mixed occurrences of both separators.
    */
    public func spm_chomp(separator: String? = nil) -> String {
        func scrub(_ separator: String) -> String {
            var E = endIndex
            while String(self[startIndex..<E]).hasSuffix(separator) && E > startIndex {
                E = index(before: E)
            }
            return String(self[startIndex..<E])
        }

        if let separator = separator {
            return scrub(separator)
        } else if hasSuffix("\r\n") {
            return scrub("\r\n")
        } else if hasSuffix("\n") {
            return scrub("\n")
        } else {
            return self
        }
    }

    /**
     Trims whitespace from both ends of a string, if the resulting
     string is empty, returns `nil`.String
     
     Useful because you can short-circuit off the result and thus
     handle “falsy” strings in an elegant way:
     
         return userInput.chuzzle() ?? "default value"
    */
    public func spm_chuzzle() -> String? {
        var cc = self

        loop: while true {
            switch cc.first {
            case nil:
                return nil
            case "\n"?, "\r"?, " "?, "\t"?, "\r\n"?:
                cc = String(cc.dropFirst())
            default:
                break loop
            }
        }

        loop: while true {
            switch cc.last {
            case nil:
                return nil
            case "\n"?, "\r"?, " "?, "\t"?, "\r\n"?:
                cc = String(cc.dropLast())
            default:
                break loop
            }
        }

        return String(cc)
    }

    /// Splits string around a delimiter string into up to two substrings
    /// If delimiter is not found, the second returned substring is nil
    public func spm_split(around delimiter: String) -> (String, String?) {
        let comps = self.spm_split(around: Array(delimiter))
        let head = String(comps.0)
        if let tail = comps.1 {
            return (head, String(tail))
        } else {
            return (head, nil)
        }
    }

    /// Drops the given suffix from the string, if present.
    public func spm_dropSuffix(_ suffix: String) -> String {
        if hasSuffix(suffix) {
           return String(dropLast(suffix.count))
        }
        return self
    }

    public func spm_dropGitSuffix() -> String {
        return spm_dropSuffix(".git")
    }

    public func spm_multilineIndent(count: Int) -> String {
        let indent = String(repeating: " ", count: count)
        return self
            .split(separator: "\n")
            .map { indent + $0 }
            .joined(separator: "\n")
    }

    @inlinable
    public init(tsc_fromUTF8 bytes: Array<UInt8>) {
        if let string = bytes.withContiguousStorageIfAvailable({ bptr in
            String(decoding: bptr, as: UTF8.self)
        }) {
            self = string
        } else {
            self = bytes.withUnsafeBufferPointer { ubp in
                String(decoding: ubp, as: UTF8.self)
            }
        }
    }

    @inlinable
    public init(tsc_fromUTF8 bytes: ArraySlice<UInt8>) {
        if let string = bytes.withContiguousStorageIfAvailable({ bptr in
            String(decoding: bptr, as: UTF8.self)
        }) {
            self = string
        } else {
            self = bytes.withUnsafeBufferPointer { ubp in
                String(decoding: ubp, as: UTF8.self)
            }
        }
    }

    @inlinable
    public init(tsc_fromUTF8 bytes: Data) {
        self = String(decoding: bytes, as: UTF8.self)
    }

}