WebURL Documentation Beta

Structure Web​URL.​Path​Components

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.

Member Of

WebURL

A Uniform Resource Locator (URL) is a universal identifier, which often describes the location of a resource.

Conforms To

BidirectionalCollection

Properties

start​Index

public var startIndex: Index 

end​Index

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 

form​Index(after:​)

public func formIndex(after i: inout Index) 

index(before:​)

public func index(before i: Index) -> Index 

form​Index(before:​)

public func formIndex(before i: inout Index) 

replace​Subrange(_:​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

bounds Range<Index>

The subrange of the path to replace. The bounds of the range must be valid path-component indices.

new​Components 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.

replace​Subrange(_:​with​Percent​Encoded​Components:​)

@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

bounds

The subrange of the path to replace. The bounds of the range must be valid path-component indices.

new​Components 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(contents​Of:​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

new​Components Components

The new components to insert into the path.

position Index

The position at which to insert the new components. position must be a valid path component index.

Returns

A new range of indices corresponding to the location of the new components in the path.

append(contents​Of:​)

@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

new​Components 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.

remove​Subrange(_:​)

@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

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.

replace​Component(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

position Index

The position of the component to replace. position must be a valid path component index.

new​Component 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

new​Component Component

The new component to insert into the path.

position Index

The position at which to insert the new component. position must be a valid path component index.

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

new​Component 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

position Index

The index of the component to remove. position must be a valid path component index.

Returns

The index corresponding to the component following position, after modification.

remove​Last(_:​)

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

k Int

The number of elements to remove from the path. k must be greater than or equal to zero and must not exceed the number of components in the path.

ensure​Directory​Path()

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.