Structure
WebURL.PathComponents
public struct PathComponents
A view of the components in a URL's path.
This collection provides efficient, bidirectional, read-write access to the URL's path components. Components are percent-decoded when they are returned and percent-encoded when they are replaced.
var url = WebURL("http://example.com/swift/packages/%F0%9F%A6%86%20tracker")!
url.pathComponents.first! // "swift"
url.pathComponents.last! // "🦆 tracker"
url.pathComponents.removeLast()
url.pathComponents.append("swift-url")
print(url) // Prints "http://example.com/swift/packages/swift-url"
Path components extend from their leading slash until the leading slash of the next component (or the end of the path). That means that a URL whose
path is "/" contains a single, empty path component, and paths which end with a "/" (also referred to as directory paths) end with an empty component.
When appending to a directory path (through append
or any other function which replaces path components), this empty component is dropped
so that the result does not contain excessive empties. To create a directory path, append an empty component or call ensureDirectoryPath
.
var url = WebURL("file:///")!
url.pathComponents.last! // ""
url.pathComponents.count // 1
url.pathComponents.append("usr") // file:///usr
url.pathComponents.count // 1, because the trailing empty component was dropped.
url.pathComponents += ["bin", "swift"] // file:///usr/bin/swift
url.pathComponents.last! // "swift"
url.pathComponents.count // 3
url.pathComponents.ensureDirectoryPath() // file:///usr/bin/swift/
url.pathComponents.last! // ""
url.pathComponents.count // 4
Modifying the URL, such as by setting its path
or any other properties, invalidates all previously obtained path component indices.
Functions which modify the path components return new indices which may be used to maintain position across modifications.
It is best to avoid making assumptions about how this collection's count
is affected by a modification. In addition to the dropping of trailing empty
components described above, URLs with particular schemes are forbidden from ever having empty paths; attempting to remove all of the path components
from such a URL will result in a path with a single, empty component, just like setting the empty string to the URL's path
property.
Accessing this view is invalid and triggers a runtime error if the URL has an opaque path. Almost all URLs have non-opaque paths (in particular, URLs with special schemes, such as http/s and file, always have non-opaque paths). A URL with an opaque path can be recognized by the lack of slashes immediately following its scheme, for example:
-
mailto:bob@example.com
-
javascript:alert("hello");
-
data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==
See the WebURL.hasOpaquePath
property for more information.
Relationships
Member Of
WebURL
A Uniform Resource Locator (URL) is a universal identifier, which often describes the location of a resource.
Conforms To
BidirectionalCollection
Properties
startIndex
public var startIndex: Index
endIndex
public var endIndex: Index
Methods
distance(from:to:)
public func distance(from start: Index, to end: Index) -> Int
index(after:)
public func index(after i: Index) -> Index
formIndex(after:)
public func formIndex(after i: inout Index)
index(before:)
public func index(before i: Index) -> Index
formIndex(before:)
public func formIndex(before i: inout Index)
replaceSubrange(_:with:)
@inlinable
@discardableResult
public mutating func replaceSubrange<Components>(
_ bounds: Range<Index>, with newComponents: Components
) -> Range<Index> where Components: Collection, Components.Element: StringProtocol
Replaces the specified subrange of path components with the contents of the given collection.
This method has the effect of removing the specified range of components from the path, percent-encoding the new components, and inserting the
encoded components at the same location. The number of new components need not match the number of elements being removed.
If any of the new components in newComponents
are "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive),
those components are ignored.
The following example shows replacing the last 2 components of a file:
URL with an array of 4 strings.
var url = WebURL("file:///usr/bin/swift")!
let lastTwo = url.pathComponents.index(url.pathComponents.endIndex, offsetBy: -2)..<url.pathComponents.endIndex
url.pathComponents.replaceSubrange(lastTwo, with: [
"lib",
"swift",
"linux",
"libswiftCore.so"
])
print(url) // Prints "file:///usr/lib/swift/linux/libswiftCore.so"
If you pass a zero-length range as the bounds
parameter, this method inserts the elements of newComponents
at bounds.lowerBound
.
Calling the insert(contentsOf:at:)
method instead is preferred. If inserting at the end of a path whose last component is empty (i.e. a directory path),
the empty component at the end of the path will be dropped before inserting the new components.
Note how the following example inserts 2 components at the end of a path which already contains 2 components (the last of which is empty), resulting in a path with only 3 components:
var url = WebURL("file:///usr/")!
url.pathComponents.last! // ""
url.pathComponents.count // 2
url.pathComponents.replaceSubrange(
url.pathComponents.endIndex..<url.pathComponents.endIndex, with: ["bin", "swift"]
)
print(url) // Prints "file:///usr/bin/swift"
url.pathComponents.last! // "swift"
url.pathComponents.count // 3
If newComponents
does not contain any insertable components (i.e. it has a count
of 0, or contains only "." or ".." components),
this method removes the components in the given subrange without replacement. Calling the removeSubrange(_:)
method instead is preferred.
URLs with particular schemes are forbidden from ever having empty paths; attempting to remove all of the path components
from such a URL will result in a path with a single, empty component, just like setting the empty string to the URL's path
property.
var url = WebURL("http://example.com/awesome_product/index.html")!
url.pathComponents.first! // "awesome_product"
url.pathComponents.count // 2
url.pathComponents.replaceSubrange(
url.pathComponents.startIndex..<url.pathComponents.endIndex, with: [] as [String]
)
print(url) // Prints "http://example.com/"
url.pathComponents.first! // ""
url.pathComponents.count // 1
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
bounds | Range<Index> |
The subrange of the path to replace. The bounds of the range must be valid path-component indices. |
newComponents | Components |
The new components to add to the path. |
Returns
A new range of indices corresponding to the location of the new components in the path.
replaceSubrange(_:withPercentEncodedComponents:)
@inlinable
@discardableResult
public mutating func replaceSubrange<Components>(
_ range: Range<Index>, withPercentEncodedComponents newComponents: Components
) -> Range<Index> where Components: Collection, Components.Element: StringProtocol
Replaces the specified subrange of path components with the contents of the given collection.
This method has the effect of removing the specified range of components from the path, percent-encoding the new components, and inserting the
encoded components at the same location. The number of new components need not match the number of elements being removed.
If any of the new components in newComponents
are "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive),
those components are ignored.
This method behaves identically to replaceSubrange(_:with:)
, except that the contents of newComponents
are assumed to be
percent-encoded already. Additional percent-encoding will be added as necessary, but existing "%XX" elements will not be double-encoded.
The following example demonstrates this difference.
let url = WebURL("http://example.com/music/bands")!
// replaceSubrange(_:with:) preserves the given components exactly,
// which can double-encode components that are already percent-encoded.
// "%20" is a percent-encoded space.
var urlA = url
urlA.pathComponents.replaceSubrange(
urlA.pathComponents.endIndex..<urlA.pathComponents.endIndex,
with: ["The%20Beatles"]
)
urlA // "http://example.com/music/bands/The%2520Beatles"
// Use replaceSubrange(_:withPercentEncodedComponents:) if the component
// is already percent-encoded, to avoid double-encoding.
var urlB = url
urlB.pathComponents.replaceSubrange(
urlB.pathComponents.endIndex..<urlB.pathComponents.endIndex,
withPercentEncodedComponents: ["The%20Beatles"]
)
urlB // "http://example.com/music/bands/The%20Beatles"
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
bounds | The subrange of the path to replace. The bounds of the range must be valid path-component indices. |
|
newComponents | Components |
The new components to add to the path. |
Returns
A new range of indices corresponding to the location of the new components in the path.
insert(contentsOf:at:)
@inlinable
@discardableResult
public mutating func insert<Components>(
contentsOf newComponents: Components, at position: Index
) -> Range<Index> where Components: Collection, Components.Element: StringProtocol
Inserts the elements of a collection into the path at the specified position.
The new components are inserted before the component currently at the specified index, and their contents will be percent-encoded, if necessary. If any of the new components are "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive), those components are ignored.
The following example inserts an array of path components in the middle of a path:
var url = WebURL("file:///usr/swift")!
url.pathComponents.insert(
contentsOf: ["local", "bin"], at: url.pathComponents.index(after: url.pathComponents.startIndex)
)
print(url) // Prints "file:///usr/local/bin/swift"
If you pass the path's endIndex
property as the position
parameter, the new elements are appended to the path.
Calling the append(contentsOf:)
method instead is preferred. If inserting at the end of a path whose last component is empty (i.e. a directory path),
the trailing empty component will be dropped and replaced by the first inserted component.
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
newComponents | Components |
The new components to insert into the path. |
position | Index |
The position at which to insert the new components. |
Returns
A new range of indices corresponding to the location of the new components in the path.
append(contentsOf:)
@inlinable
@discardableResult
public mutating func append<Components>(
contentsOf newComponents: Components
) -> Range<Index> where Components: Collection, Components.Element: StringProtocol
Adds the elements of a collection to the end of this path.
The contents of the appended components will be percent-encoded, if necessary. If any of the new components are "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive), those components are ignored.
If appending to a path whose last component is empty (i.e. a directory path), the trailing empty component will be dropped and replaced by the first inserted component.
The following example builds a path by appending path components. Note that the first append
does not change the count
, as the URL initially
has a directory path.
var url = WebURL("file:///")!
url.pathComponents.last! // ""
url.pathComponents.count // 1
url.pathComponents.append(contentsOf: ["tmp"])
url.pathComponents.last! // "tmp"
url.pathComponents.count // 1
url.pathComponents.append(contentsOf: ["my_app", "data.json"])
url.pathComponents.last! // "data.json"
url.pathComponents.count // 3
print(url) // Prints "file:///tmp/my_app/data.json"
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
newComponents | Components |
The new components to add to end of the path. |
Returns
A new range of indices corresponding to the location of the new components in the path.
removeSubrange(_:)
@discardableResult
public mutating func removeSubrange(_ bounds: Range<Index>) -> Index
Removes the specified subrange of components from the path.
var url = WebURL("http://example.com/projects/swift/swift-url/0.2.0/")!
url.pathComponents.removeSubrange(
url.pathComponents.index(after: url.pathComponents.startIndex)..<url.pathComponents.endIndex
)
print(url) // Prints "http://example.com/projects"
URLs with particular schemes are forbidden from ever having empty paths; attempting to remove all of the path components
from such a URL will result in a path with a single, empty component, just like setting the empty string to the URL's path
property.
var url = WebURL("http://example.com/awesome_product/index.html")!
url.pathComponents.removeSubrange(
url.pathComponents.startIndex..<url.pathComponents.endIndex
)
print(url) // Prints "http://example.com/"
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
bounds | Range<Index> |
The subrange of the path to remove. The bounds of the range must be valid path component indices. |
Returns
The index corresponding to the subrange's upperBound
after modification.
replaceComponent(at:with:)
@inlinable
@discardableResult
public mutating func replaceComponent<Component>(
at position: Index, with newComponent: Component
) -> Range<Index> where Component: StringProtocol
Replaces the path component at the specified position.
The contents of the new component will be percent-encoded, if necessary.
var url = WebURL("file:///usr/bin/swift")!
url.pathComponents.replaceComponent(
at: url.pathComponents.index(after: url.pathComponents.startIndex),
with: "lib"
)
print(url) // Prints "file:///usr/lib/swift"
If the new component is "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive), the component at position
is removed -
as if calling replaceSubrange
with an empty collection.
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
position | Index |
The position of the component to replace. |
newComponent | Component |
The value to set the component to. |
Returns
A new range of indices encompassing the replaced component.
insert(_:at:)
@inlinable
@discardableResult
public mutating func insert<Component>(
_ newComponent: Component, at position: Index
) -> Range<Index> where Component: StringProtocol
Inserts a component into the path at the specified position.
The new component is inserted before the component currently at the specified index, and its contents will be percent-encoded, if necessary. If the new component is "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive), it is ignored.
The following example inserts a component in the middle of a path:
var url = WebURL("file:///usr/swift")!
url.pathComponents.insert(
"bin",
at: url.pathComponents.index(after: url.pathComponents.startIndex)
)
print(url) // Prints "file:///usr/bin/swift"
If you pass the path's endIndex
property as the position
parameter, the new component is appended to the path.
Calling the append(_:)
method instead is preferred. If inserting at the end of a path whose last component is empty (i.e. a directory path),
the trailing empty component will be dropped and replaced by the new component.
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
newComponent | Component |
The new component to insert into the path. |
position | Index |
The position at which to insert the new component. |
Returns
A new range of indices corresponding to the location of the new component in the path.
append(_:)
@inlinable
@discardableResult
public mutating func append<Component>(
_ newComponent: Component
) -> Index where Component: StringProtocol
Adds a component to the end of this path.
The contents of the appended component will be percent-encoded, if necessary. If the new component is "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive), it will be ignored.
If appending to a path whose last component is empty (i.e. a directory path), the trailing empty component will be dropped and replaced by the new component.
The following example builds a path by appending components. Note that the first append
does not change the count
, as the URL initially
has a directory path.
var url = WebURL("file:///")!
url.pathComponents.last! // ""
url.pathComponents.count // 1
url.pathComponents.append("tmp")
url.pathComponents.last! // "tmp"
url.pathComponents.count // 1
url.pathComponents.append("data.json")
url.pathComponents.last! // "data.json"
url.pathComponents.count // 2
print(url) // Prints "file:///tmp/data.json"
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
newComponent | Component |
The new component to add to end of the path. |
Returns
The location of the new component in the path.
remove(at:)
@discardableResult
public mutating func remove(at position: Index) -> Index
Removes the component at the given index from the path.
var url = WebURL("http://example.com/projects/swift/swift-url/0.2.0/Sources/")!
url.pathComponents.remove(
at: url.pathComponents.index(after: url.pathComponents.startIndex)
)
print(url) // Prints "http://example.com/projects/swift-url/0.2.0/Sources/"
URLs with particular schemes are forbidden from ever having empty paths; attempting to remove all of the path components
from such a URL will result in a path with a single, empty component, just like setting the empty string to the URL's path
property.
var url = WebURL("http://example.com/foo")!
url.pathComponents.remove(at: url.pathComponents.startIndex)
print(url) // Prints "http://example.com/"
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
position | Index |
The index of the component to remove. |
Returns
The index corresponding to the component following position
, after modification.
removeLast(_:)
public mutating func removeLast(_ k: Int = 1)
Removes the specified number of components from the end of the path.
Attempting to remove more components than exist in the path triggers a runtime error.
var url = WebURL("http://example.com/foo/bar")!
url.pathComponents.removeLast()
print(url) // Prints "http://example.com/foo"
url.pathComponents.removeLast()
print(url) // Prints "http://example.com/"
URLs with particular schemes are forbidden from ever having empty paths; attempting to remove all of the path components
from such a URL will result in a path with a single, empty component, just like setting the empty string to the URL's path
property.
Calling this method invalidates any existing indices for this URL.
Parameters
Name | Type | Description |
---|---|---|
k | Int |
The number of elements to remove from the path. |
ensureDirectoryPath()
public mutating func ensureDirectoryPath()
Appends an empty component to the path, if it does not already end with an empty component. This has the effect of ensuring the path ends with a trailing slash.
The following example demonstrates building a file path by appending components,
and finishes by using ensureDirectoryPath
to ensure the path ends in a trailing slash:
var url = WebURL("file:///")!
url.pathComponents += ["Users", "karl", "Desktop"] // "file:///Users/karl/Desktop"
url.pathComponents.ensureDirectoryPath() // "file:///Users/karl/Desktop/"
If the path is already a directory path, this method has no effect.
Operators
+=
@inlinable
public static func += <Components>(
lhs: inout WebURL.PathComponents, rhs: Components
) where Components: Collection, Components.Element: StringProtocol
Adds the elements of a collection to the end of this path.
The contents of the appended components will be percent-encoded, if necessary. If any of the new components are "." or ".." (or their percent-encoded versions, "%2E" or "%2E%2E", case-insensitive), those components are ignored.
If appending to a path whose last component is empty (i.e. a directory path), the trailing empty component will be dropped and replaced by the first inserted component.
The following example builds a path by appending path components. Note that the first +=
does not change the count
, as the URL initially
has a directory path.
var url = WebURL("file:///")!
url.pathComponents.last! // ""
url.pathComponents.count // 1
url.pathComponents += ["tmp"]
url.pathComponents.last! // "tmp"
url.pathComponents.count // 1
url.pathComponents += ["my_app", "data.json"]
url.pathComponents.last! // "data.json"
url.pathComponents.count // 3
print(url) // Prints "file:///tmp/my_app/data.json"
Calling this method invalidates any existing indices for this URL.