mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
190 lines
6.7 KiB
Swift
190 lines
6.7 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SwiftShims
|
|
|
|
extension String {
|
|
/// Creates a new string representing the given string repeated the specified
|
|
/// number of times.
|
|
///
|
|
/// For example, you can use this initializer to create a string with ten
|
|
/// `"ab"` strings in a row.
|
|
///
|
|
/// let s = String(repeating: "ab", count: 10)
|
|
/// print(s)
|
|
/// // Prints "abababababababababab"
|
|
///
|
|
/// - Parameters:
|
|
/// - repeatedValue: The string to repeat.
|
|
/// - count: The number of times to repeat `repeatedValue` in the resulting
|
|
/// string.
|
|
public init(repeating repeatedValue: String, count: Int) {
|
|
_precondition(count >= 0, "Negative count not allowed")
|
|
guard count > 1 else {
|
|
self = count == 0 ? "" : repeatedValue
|
|
return
|
|
}
|
|
|
|
// TODO(String performance): We can directly call appendInPlace
|
|
var result = String()
|
|
result.reserveCapacity(repeatedValue._guts.count &* count)
|
|
for _ in 0..<count {
|
|
result += repeatedValue
|
|
}
|
|
self = result
|
|
}
|
|
|
|
/// A Boolean value indicating whether a string has no characters.
|
|
@inlinable
|
|
public var isEmpty: Bool {
|
|
@inline(__always) get { return _guts.isEmpty }
|
|
}
|
|
}
|
|
|
|
extension StringProtocol {
|
|
/// Returns a Boolean value indicating whether the string begins with the
|
|
/// specified prefix.
|
|
///
|
|
/// The comparison is both case sensitive and Unicode safe. The
|
|
/// case-sensitive comparison will only match strings whose corresponding
|
|
/// characters have the same case.
|
|
///
|
|
/// let cafe = "Café du Monde"
|
|
///
|
|
/// // Case sensitive
|
|
/// print(cafe.hasPrefix("café"))
|
|
/// // Prints "false"
|
|
///
|
|
/// The Unicode-safe comparison matches Unicode extended grapheme clusters
|
|
/// rather than the code points used to compose them. The example below uses
|
|
/// two strings with different forms of the `"é"` character---the first uses
|
|
/// the composed form and the second uses the decomposed form.
|
|
///
|
|
/// // Unicode safe
|
|
/// let composedCafe = "Café"
|
|
/// let decomposedCafe = "Cafe\u{0301}"
|
|
///
|
|
/// print(cafe.hasPrefix(composedCafe))
|
|
/// // Prints "true"
|
|
/// print(cafe.hasPrefix(decomposedCafe))
|
|
/// // Prints "true"
|
|
///
|
|
/// - Parameter prefix: A possible prefix to test against this string.
|
|
/// - Returns: `true` if the string begins with `prefix`; otherwise, `false`.
|
|
@inlinable
|
|
public func hasPrefix<Prefix: StringProtocol>(_ prefix: Prefix) -> Bool {
|
|
return self.starts(with: prefix)
|
|
}
|
|
|
|
/// Returns a Boolean value indicating whether the string ends with the
|
|
/// specified suffix.
|
|
///
|
|
/// The comparison is both case sensitive and Unicode safe. The
|
|
/// case-sensitive comparison will only match strings whose corresponding
|
|
/// characters have the same case.
|
|
///
|
|
/// let plans = "Let's meet at the café"
|
|
///
|
|
/// // Case sensitive
|
|
/// print(plans.hasSuffix("Café"))
|
|
/// // Prints "false"
|
|
///
|
|
/// The Unicode-safe comparison matches Unicode extended grapheme clusters
|
|
/// rather than the code points used to compose them. The example below uses
|
|
/// two strings with different forms of the `"é"` character---the first uses
|
|
/// the composed form and the second uses the decomposed form.
|
|
///
|
|
/// // Unicode safe
|
|
/// let composedCafe = "café"
|
|
/// let decomposedCafe = "cafe\u{0301}"
|
|
///
|
|
/// print(plans.hasSuffix(composedCafe))
|
|
/// // Prints "true"
|
|
/// print(plans.hasSuffix(decomposedCafe))
|
|
/// // Prints "true"
|
|
///
|
|
/// - Parameter suffix: A possible suffix to test against this string.
|
|
/// - Returns: `true` if the string ends with `suffix`; otherwise, `false`.
|
|
@inlinable
|
|
public func hasSuffix<Suffix: StringProtocol>(_ suffix: Suffix) -> Bool {
|
|
return self.reversed().starts(with: suffix.reversed())
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
public func hasPrefix(_ prefix: String) -> Bool {
|
|
if _fastPath(self._guts.isNFCFastUTF8 && prefix._guts.isNFCFastUTF8) {
|
|
guard prefix._guts.count <= self._guts.count else { return false }
|
|
return prefix._guts.withFastUTF8 { nfcPrefix in
|
|
let prefixEnd = nfcPrefix.count
|
|
return self._guts.withFastUTF8(range: 0..<prefixEnd) { nfcSlicedSelf in
|
|
return _binaryCompare(nfcSlicedSelf, nfcPrefix) == 0
|
|
}
|
|
}
|
|
}
|
|
|
|
return starts(with: prefix)
|
|
}
|
|
|
|
public func hasSuffix(_ suffix: String) -> Bool {
|
|
if _fastPath(self._guts.isNFCFastUTF8 && suffix._guts.isNFCFastUTF8) {
|
|
guard suffix._guts.count <= self._guts.count else { return false }
|
|
return suffix._guts.withFastUTF8 { nfcSuffix in
|
|
let suffixStart = self._guts.count - nfcSuffix.count
|
|
return self._guts.withFastUTF8(range: suffixStart..<self._guts.count) {
|
|
nfcSlicedSelf in return _binaryCompare(nfcSlicedSelf, nfcSuffix) == 0
|
|
}
|
|
}
|
|
}
|
|
|
|
return self.reversed().starts(with: suffix.reversed())
|
|
}
|
|
}
|
|
|
|
// Conversions to string from other types.
|
|
extension String {
|
|
/// Creates a string representing the given value in base 10, or some other
|
|
/// specified base.
|
|
///
|
|
/// The following example converts the maximal `Int` value to a string and
|
|
/// prints its length:
|
|
///
|
|
/// let max = String(Int.max)
|
|
/// print("\(max) has \(max.count) digits.")
|
|
/// // Prints "9223372036854775807 has 19 digits."
|
|
///
|
|
/// Numerals greater than 9 are represented as Roman letters. These letters
|
|
/// start with `"A"` if `uppercase` is `true`; otherwise, with `"a"`.
|
|
///
|
|
/// let v = 999_999
|
|
/// print(String(v, radix: 2))
|
|
/// // Prints "11110100001000111111"
|
|
///
|
|
/// print(String(v, radix: 16))
|
|
/// // Prints "f423f"
|
|
/// print(String(v, radix: 16, uppercase: true))
|
|
/// // Prints "F423F"
|
|
///
|
|
/// - Parameters:
|
|
/// - value: The value to convert to a string.
|
|
/// - radix: The base to use for the string representation. `radix` must be
|
|
/// at least 2 and at most 36. The default is 10.
|
|
/// - uppercase: Pass `true` to use uppercase letters to represent numerals
|
|
/// greater than 9, or `false` to use lowercase letters. The default is
|
|
/// `false`.
|
|
public init<T: BinaryInteger>(
|
|
_ value: T, radix: Int = 10, uppercase: Bool = false
|
|
) {
|
|
self = value._description(radix: radix, uppercase: uppercase)
|
|
}
|
|
}
|