Swift: extract string with regex and range In Swift, I have a string like this 


  http://mnc-hdqp.oss-cn-shanghai.aliyuncs.com/user%2Fheat%2Fdefault.jpg?Signature=2BI%2BauSvy&amp;Expires=1568682491&amp;OSSAccessKeyId=LTAIQ8Lif1HHVkXd


Need to extract 2BI%2BauSvy, the value of key Signature

here is code: regex match, then use range to subtract the key ahead.

let key = "Signature"
let signatures = icon.matches(for: "\(key)[^&amp;]+")
guard !signatures.isEmpty else{
     return
}
if let range = signatures[0].range(of: "\(key)="){
      let signature = String(signatures[0][range.upperBound...])
      print(signature)
}


Any way to implement it conveniently? 



PS: func matches(for:)

extension String{

    func matches(for regex: String) -&gt; [String] {

        do {
            let regex = try NSRegularExpression(pattern: regex)
            let results = regex.matches(in: self,
                                        range: NSRange(self.startIndex..., in: self))
            return results.map {
                String(self[Range($0.range, in: self)!])
            }
        } catch let error {
            print("invalid regex: \(error.localizedDescription)")
            return []
        }
    }
Simplify the code

The guard statement and the following if let can be combined into a single statement:

let key = "Signature"
let signatures = iconURL.matches(for: "\(key)[^&amp;]+")
if let firstSignature = signatures.first,
    let range = firstSignature.range(of: "\(key)=") {
    let signature = String(firstSignature[range.upperBound...])
    print(signature)
}


Improve the regex pattern

Your method is fragile because the key "Signature" may occur in the host part of the URL. Here is an example where it fails:

let iconURL = "http://Signature.com/?a=b&amp;Signature=sig&amp;c=d"


As mentioned in the comments, you can use a positive look-behind which includes the "=" character:

let key = "Signature"
let signatures = iconURL.matches(for: "(?&lt;=\(key)=)[^&amp;]+")
if let signature = signatures.first {
    print(signature)
}


However, this would still fail for 

let iconURL = "http://foo.com/Signature=bar?a=b&amp;Signature=sig&amp;c=d"


because the "=" character is valid in the path part of an URL.

You also must ensure that the key does not contain any characters which have a special meaning in a regex pattern.

And now for something completely different

The Foundation framework has a dedicated URLComponents type to parse URLs into their parts. It does exactly what you need here:

let iconURL = "http://Signature.com/Signature=foo?a=b&amp;Signature=2BI%2BauSvy&amp;c=d"
let key = "Signature"

if let urlComponents = URLComponents(string: iconURL),
    let queryItems = urlComponents.queryItems {
    for queryItem in queryItems where queryItem.name == key {
        if let value = queryItem.value {
            print(value) // 2BI+auSvy
        }
    }
}


In addition, the value is already percent-decoded.