mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
It is still possible to get the same behavior by providing an explicit
type context, or in a generic code, but otherwise, `String("")!` will
not compile.
426 lines
16 KiB
Plaintext
426 lines
16 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension String : StringProtocol {
|
|
/// The index type for subscripting a string.
|
|
public typealias Index = CharacterView.Index
|
|
|
|
/// A type that represents the number of steps between two `String.Index`
|
|
/// values, where one value is reachable from the other.
|
|
///
|
|
/// In Swift, *reachability* refers to the ability to produce one value from
|
|
/// the other through zero or more applications of `index(after:)`.
|
|
public typealias IndexDistance = CharacterView.IndexDistance
|
|
|
|
public typealias SubSequence = Substring
|
|
|
|
/// Creates a string representing the given character repeated the specified
|
|
/// number of times.
|
|
///
|
|
/// For example, use this initializer to create a string with ten `"0"`
|
|
/// characters in a row.
|
|
///
|
|
/// let zeroes = String("0" as Character, count: 10)
|
|
/// print(zeroes)
|
|
/// // Prints "0000000000"
|
|
public init(repeating repeatedValue: Character, count: Int) {
|
|
self.init(repeating: String(repeatedValue), count: count)
|
|
}
|
|
|
|
// FIXME(strings): doc comment
|
|
// This initializer satisfies the conformance to LosslessStringConvertible
|
|
// and disambiguates between the following intitializers, now that String
|
|
// conforms to Collection:
|
|
// - init<T>(_ value: T) where T : LosslessStringConvertible
|
|
// - init<S>(_ characters: S) where S : Sequence, S.Iterator.Element == Character
|
|
public init(_ other: String) {
|
|
self.init(other._core)
|
|
}
|
|
|
|
/// The position of the first character in a nonempty string.
|
|
///
|
|
/// In an empty string, `startIndex` is equal to `endIndex`.
|
|
public var startIndex: Index { return characters.startIndex }
|
|
|
|
/// A string's "past the end" position---that is, the position one greater
|
|
/// than the last valid subscript argument.
|
|
///
|
|
/// In an empty string, `endIndex` is equal to `startIndex`.
|
|
public var endIndex: Index { return characters.endIndex }
|
|
|
|
/// Returns the position immediately after the given index.
|
|
///
|
|
/// - Parameter i: A valid index of the collection. `i` must be less than
|
|
/// `endIndex`.
|
|
/// - Returns: The index value immediately after `i`.
|
|
public func index(after i: Index) -> Index {
|
|
return characters.index(after: i)
|
|
}
|
|
|
|
// TODO: swift-3-indexing-model - add docs
|
|
public func index(before i: Index) -> Index {
|
|
return characters.index(before: i)
|
|
}
|
|
|
|
/// Returns an index that is the specified distance from the given index.
|
|
///
|
|
/// The following example obtains an index advanced four positions from a
|
|
/// string's starting index and then prints the character at that position.
|
|
///
|
|
/// let s = "Swift"
|
|
/// let i = s.index(s.startIndex, offsetBy: 4)
|
|
/// print(s[i])
|
|
/// // Prints "t"
|
|
///
|
|
/// The value passed as `n` must not offset `i` beyond the bounds of the
|
|
/// collection.
|
|
///
|
|
/// - Parameters:
|
|
/// - i: A valid index of the collection.
|
|
/// - n: The distance to offset `i`.
|
|
/// - Returns: An index offset by `n` from the index `i`. If `n` is positive,
|
|
/// this is the same value as the result of `n` calls to `index(after:)`.
|
|
/// If `n` is negative, this is the same value as the result of `-n` calls
|
|
/// to `index(before:)`.
|
|
///
|
|
/// - SeeAlso: `index(_:offsetBy:limitedBy:)`
|
|
/// - Complexity: O(*n*), where *n* is the absolute value of `n`.
|
|
public func index(_ i: Index, offsetBy n: IndexDistance) -> Index {
|
|
return characters.index(i, offsetBy: n)
|
|
}
|
|
|
|
/// Returns an index that is the specified distance from the given index,
|
|
/// unless that distance is beyond a given limiting index.
|
|
///
|
|
/// The following example obtains an index advanced four positions from a
|
|
/// string's starting index and then prints the character at that position.
|
|
/// The operation doesn't require going beyond the limiting `s.endIndex`
|
|
/// value, so it succeeds.
|
|
///
|
|
/// let s = "Swift"
|
|
/// if let i = s.index(s.startIndex, offsetBy: 4, limitedBy: s.endIndex) {
|
|
/// print(s[i])
|
|
/// }
|
|
/// // Prints "t"
|
|
///
|
|
/// The next example attempts to retrieve an index six positions from
|
|
/// `s.startIndex` but fails, because that distance is beyond the index
|
|
/// passed as `limit`.
|
|
///
|
|
/// let j = s.index(s.startIndex, offsetBy: 6, limitedBy: s.endIndex)
|
|
/// print(j)
|
|
/// // Prints "nil"
|
|
///
|
|
/// The value passed as `n` must not offset `i` beyond the bounds of the
|
|
/// collection, unless the index passed as `limit` prevents offsetting
|
|
/// beyond those bounds.
|
|
///
|
|
/// - Parameters:
|
|
/// - i: A valid index of the collection.
|
|
/// - n: The distance to offset `i`.
|
|
/// - limit: A valid index of the collection to use as a limit. If `n > 0`,
|
|
/// a limit that is less than `i` has no effect. Likewise, if `n < 0`, a
|
|
/// limit that is greater than `i` has no effect.
|
|
/// - Returns: An index offset by `n` from the index `i`, unless that index
|
|
/// would be beyond `limit` in the direction of movement. In that case,
|
|
/// the method returns `nil`.
|
|
///
|
|
/// - SeeAlso: `index(_:offsetBy:)`
|
|
/// - Complexity: O(*n*), where *n* is the absolute value of `n`.
|
|
public func index(
|
|
_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index
|
|
) -> Index? {
|
|
return characters.index(i, offsetBy: n, limitedBy: limit)
|
|
}
|
|
|
|
/// Returns the distance between two indices.
|
|
///
|
|
/// - Parameters:
|
|
/// - start: A valid index of the collection.
|
|
/// - end: Another valid index of the collection. If `end` is equal to
|
|
/// `start`, the result is zero.
|
|
/// - Returns: The distance between `start` and `end`.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the resulting distance.
|
|
public func distance(from start: Index, to end: Index) -> IndexDistance {
|
|
return characters.distance(from: start, to: end)
|
|
}
|
|
|
|
/// Accesses the character at the given position.
|
|
///
|
|
/// Indices for a subscripting a string are shared with the string's
|
|
/// `characters` view. For example:
|
|
///
|
|
/// let greeting = "Hello, friend!"
|
|
/// if let i = greeting.characters.index(where: { $0 >= "A" && $0 <= "Z" }) {
|
|
/// print("First capital letter: \(greeting[i])")
|
|
/// }
|
|
/// // Prints "First capital letter: H"
|
|
///
|
|
/// - Parameter i: A valid index of the string. `i` must be less than the
|
|
/// string's end index.
|
|
public subscript(i: Index) -> Character { return characters[i] }
|
|
}
|
|
|
|
extension String.Index {
|
|
public static func == (lhs: String.Index, rhs: String.Index) -> Bool {
|
|
return lhs._base == rhs._base
|
|
}
|
|
|
|
public static func < (lhs: String.Index, rhs: String.Index) -> Bool {
|
|
return lhs._base < rhs._base
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
/// Creates a new string containing the characters in the given sequence.
|
|
///
|
|
/// You can use this initializer to create a new string from the result of
|
|
/// one or more operations on a string's `characters` view. For example:
|
|
///
|
|
/// let str = "The rain in Spain stays mainly in the plain."
|
|
///
|
|
/// let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
|
|
/// let disemvoweled = String(str.characters.lazy.filter { !vowels.contains($0) })
|
|
///
|
|
/// print(disemvoweled)
|
|
/// // Prints "Th rn n Spn stys mnly n th pln."
|
|
///
|
|
/// - Parameter characters: A sequence of characters.
|
|
public init<S : Sequence>(_ characters: S)
|
|
where S.Iterator.Element == Character {
|
|
self._core = CharacterView(characters)._core
|
|
}
|
|
|
|
/// Reserves enough space in the string's underlying storage to store the
|
|
/// specified number of ASCII characters.
|
|
///
|
|
/// Because each character in a string can require more than a single ASCII
|
|
/// character's worth of storage, additional allocation may be necessary
|
|
/// when adding characters to a string after a call to
|
|
/// `reserveCapacity(_:)`.
|
|
///
|
|
/// - Parameter n: The minimum number of ASCII character's worth of storage
|
|
/// to allocate.
|
|
///
|
|
/// - Complexity: O(*n*)
|
|
public mutating func reserveCapacity(_ n: Int) {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.reserveCapacity(n)
|
|
}
|
|
}
|
|
|
|
/// Appends the given character to the string.
|
|
///
|
|
/// The following example adds an emoji globe to the end of a string.
|
|
///
|
|
/// var globe = "Globe "
|
|
/// globe.append("🌍")
|
|
/// print(globe)
|
|
/// // Prints "Globe 🌍"
|
|
///
|
|
/// - Parameter c: The character to append to the string.
|
|
public mutating func append(_ c: Character) {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.append(c)
|
|
}
|
|
}
|
|
|
|
/// Appends the characters in the given sequence to the string.
|
|
///
|
|
/// - Parameter newElements: A sequence of characters.
|
|
public mutating func append<S : Sequence>(contentsOf newElements: S)
|
|
where S.Iterator.Element == Character {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.append(contentsOf: newElements)
|
|
}
|
|
}
|
|
|
|
/// Replaces the text within the specified bounds with the given characters.
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// string.
|
|
///
|
|
/// - Parameters:
|
|
/// - bounds: The range of text to replace. The bounds of the range must be
|
|
/// valid indices of the string.
|
|
/// - newElements: The new characters to add to the string.
|
|
///
|
|
/// - Complexity: O(*m*), where *m* is the combined length of the string and
|
|
/// `newElements`. If the call to `replaceSubrange(_:with:)` simply
|
|
/// removes text at the end of the string, the complexity is O(*n*), where
|
|
/// *n* is equal to `bounds.count`.
|
|
public mutating func replaceSubrange<C>(
|
|
_ bounds: Range<Index>,
|
|
with newElements: C
|
|
) where C : Collection, C.Iterator.Element == Character {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView)
|
|
in v.replaceSubrange(bounds, with: newElements)
|
|
}
|
|
}
|
|
|
|
/// Inserts a new character at the specified position.
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// string.
|
|
///
|
|
/// - Parameters:
|
|
/// - newElement: The new character to insert into the string.
|
|
/// - i: A valid index of the string. If `i` is equal to the string's end
|
|
/// index, this methods appends `newElement` to the string.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the length of the string.
|
|
public mutating func insert(_ newElement: Character, at i: Index) {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.insert(newElement, at: i)
|
|
}
|
|
}
|
|
|
|
/// Inserts a collection of characters at the specified position.
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// string.
|
|
///
|
|
/// - Parameters:
|
|
/// - newElements: A collection of `Character` elements to insert into the
|
|
/// string.
|
|
/// - i: A valid index of the string. If `i` is equal to the string's end
|
|
/// index, this methods appends the contents of `newElements` to the
|
|
/// string.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the combined length of the string and
|
|
/// `newElements`.
|
|
public mutating func insert<S : Collection>(
|
|
contentsOf newElements: S, at i: Index
|
|
) where S.Iterator.Element == Character {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.insert(contentsOf: newElements, at: i)
|
|
}
|
|
}
|
|
|
|
/// Removes and returns the character at the specified position.
|
|
///
|
|
/// All the elements following `i` are moved to close the gap. This example
|
|
/// removes the hyphen from the middle of a string.
|
|
///
|
|
/// var nonempty = "non-empty"
|
|
/// if let i = nonempty.characters.index(of: "-") {
|
|
/// nonempty.remove(at: i)
|
|
/// }
|
|
/// print(nonempty)
|
|
/// // Prints "nonempty"
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// string.
|
|
///
|
|
/// - Parameter i: The position of the character to remove. `i` must be a
|
|
/// valid index of the string that is not equal to the string's end index.
|
|
/// - Returns: The character that was removed.
|
|
@discardableResult
|
|
public mutating func remove(at i: Index) -> Character {
|
|
return withMutableCharacters {
|
|
(v: inout CharacterView) in v.remove(at: i)
|
|
}
|
|
}
|
|
|
|
/// Removes the characters in the given range.
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// string.
|
|
///
|
|
/// - Parameter bounds: The range of the elements to remove. The upper and
|
|
/// lower bounds of `bounds` must be valid indices of the string and not
|
|
/// equal to the string's end index.
|
|
/// - Parameter bounds: The range of the elements to remove. The upper and
|
|
/// lower bounds of `bounds` must be valid indices of the string.
|
|
public mutating func removeSubrange(_ bounds: Range<Index>) {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.removeSubrange(bounds)
|
|
}
|
|
}
|
|
|
|
/// Replaces this string with the empty string.
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// string.
|
|
///
|
|
/// - Parameter keepCapacity: Pass `true` to prevent the release of the
|
|
/// string's allocated storage. Retaining the storage can be a useful
|
|
/// optimization when you're planning to grow the string again. The
|
|
/// default value is `false`.
|
|
public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
|
|
withMutableCharacters {
|
|
(v: inout CharacterView) in v.removeAll(keepingCapacity: keepCapacity)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension String {
|
|
// This is needed because of the issue described in SR-4660 which causes
|
|
// source compatibility issues when String becomes a collection
|
|
@_transparent
|
|
public func max<T : Comparable>(_ x: T, _ y: T) -> T {
|
|
return Swift.max(x,y)
|
|
}
|
|
|
|
// This is needed because of the issue described in SR-4660 which causes
|
|
// source compatibility issues when String becomes a collection
|
|
@_transparent
|
|
public func min<T : Comparable>(_ x: T, _ y: T) -> T {
|
|
return Swift.min(x,y)
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// The following overloads of flatMap are carefully crafted to allow the code
|
|
// like the following:
|
|
// ["hello"].flatMap { $0 }
|
|
// return an array of strings without any type context in Swift 3 mode, at the
|
|
// same time allowing the following code snippet to compile:
|
|
// [0, 1].flatMap { x in
|
|
// if String(x) == "foo" { return "bar" } else { return nil }
|
|
// }
|
|
// Note that the second overload is delcared on a more specific protocol.
|
|
// See: test/stdlib/StringFlatMap.swift for tests.
|
|
extension Sequence {
|
|
@available(swift, obsoleted: 4)
|
|
public func flatMap(
|
|
_ transform: (Iterator.Element) throws -> String
|
|
) rethrows -> [String] {
|
|
return try map(transform)
|
|
}
|
|
}
|
|
|
|
extension Collection {
|
|
public func flatMap(
|
|
_ transform: (Iterator.Element) throws -> String?
|
|
) rethrows -> [String] {
|
|
return try _flatMap(transform)
|
|
}
|
|
}
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension String {
|
|
@available(*, unavailable, message: "Operator '+' cannot be used to append a String to a sequence of strings")
|
|
public static func + <S : Sequence>(lhs: S, rhs: String) -> Never
|
|
where S.Iterator.Element == String {
|
|
fatalError()
|
|
}
|
|
|
|
@available(*, unavailable, message: "Operator '+' cannot be used to append a String to a sequence of strings")
|
|
public static func + <S : Sequence>(lhs: String, rhs: S) -> Never
|
|
where S.Iterator.Element == String {
|
|
fatalError()
|
|
}
|
|
}
|