How do I convert url.query to a dictionary in Swift?

前端 未结 6 1379
不知归路
不知归路 2021-02-09 02:06

I have a URL coming in to the AppDelegate method:

func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) ->         


        
相关标签:
6条回答
  • 2021-02-09 02:17

    Simple Extension

    extension URL {
        var queryDictionary: [String: String]? {
            guard let query = self.query else { return nil}
    
            var queryStrings = [String: String]()
            for pair in query.components(separatedBy: "&") {
    
                let key = pair.components(separatedBy: "=")[0]
    
                let value = pair
                    .components(separatedBy:"=")[1]
                    .replacingOccurrences(of: "+", with: " ")
                    .removingPercentEncoding ?? ""
    
                queryStrings[key] = value
            }
            return queryStrings
        }
    }
    

    USAGE

    let urlString = "http://www.youtube.com/video/4bL4FI1Gz6s?hl=it_IT&iv_logging_level=3&ad_flags=0&endscreen_module=http://s.ytimg.com/yt/swfbin/endscreen-vfl6o3XZn.swf&cid=241&cust_gender=1&avg_rating=4.82280613104"
    let url = URL(string: urlString)
    print(url!.queryDictionary ?? "NONE")
    
    0 讨论(0)
  • 2021-02-09 02:21

    Use:

    guard let urlQuery =  URL(string: "https://en.wikipedia.org/wiki/Query_string?title=Main_page&action=raw")?.query else {
        return
    }
    
    let queryArray = urlQuery.characters.split { $0 == "&"}.map(String.init)
    var parametersDict: [String: String] = [:]
    for queryParameter in queryArray {
        // Split the queryParam into key / value
        let keyValueArray = queryParameter.characters.split{$0 == "="}.map(String.init)
        let key = keyValueArray.first
        let value = keyValueArray.last
        parametersDict.updateValue(value!, forKey: key!)
    }
    
    print(parametersDict)
    // Prints ["action": "raw", "title": "Main_page"]
    
    0 讨论(0)
  • 2021-02-09 02:24

    Here is an example using the Swift reduce function. This will turn a string like 'key1=value1&key2=value2&key3=value3' into a dictionary.

    let params = queryString.components(separatedBy: "&").map({
        $0.components(separatedBy: "=")
    }).reduce(into: [String:String]()) { dict, pair in
        if pair.count == 2 {
            dict[pair[0]] = pair[1]
        }
    }
    
    0 讨论(0)
  • 2021-02-09 02:32

    Try this alternatively:

    extension URL {
        var queryDictionary: [String: AnyObject]? {
            return URLComponents(url: self, resolvingAgainstBaseURL: false)?
                .queryItems?
                .reduce([:], combine: { (lastResult: [String: AnyObject], queryItem) -> [String: AnyObject] in
                    var result = lastResult
                    if queryItem.value?.containsString(",") ?? false {
                        let array = queryItem.value?.componentsSeparatedByString(",")
    
                        result[queryItem.name] = array
                    }
                    else {
                        result[queryItem.name] = queryItem.value
                    }
    
                    return result
                })
        }
    }
    
    0 讨论(0)
  • 2021-02-09 02:37

    Use .first(where:)

            guard let query = components.queryItems else {
                return
            }
            
            guard let accessToken = query.first(where: { $0.name == "access_token" }) else {
                return
            }
    
    0 讨论(0)
  • 2021-02-09 02:37

    Details

    • Swift 5
    • Xcode Version 10.2.1 (10E1001)

    Solution

    import Foundation
    
    // MARK: - [URLQueryItem] to [String: Any]
    
    extension Array where Element == URLQueryItem {
        func toDictionary() -> [String: Any] {
            var dictionary = [String: Any]()
            for queryItem in self {
                guard let value = queryItem.value?.toCorrectType() else { continue }
                if queryItem.name.contains("[]") {
                    let key = queryItem.name.replacingOccurrences(of: "[]", with: "")
                    let array = dictionary[key] as? [Any] ?? []
                    dictionary[key] = array + [value]
                } else {
                    dictionary[queryItem.name] = value
                }
            }
            return dictionary
        }
    }
    
    extension String {
    
        // MARK: - String to [URLQueryItem]
    
        func toURLQueryItems() -> [URLQueryItem]? {
            guard let urlString = self.removingPercentEncoding, let url = URL(string: urlString) else { return nil }
            if let querItems = url.toQueryItems() { return querItems }
            var urlComponents = URLComponents()
            urlComponents.query = urlString
            return urlComponents.queryItems
        }
    
        // MARK: - attempt to cast string to correct type (int, bool...)
    
        func toCorrectType() -> Any {
            let types: [LosslessStringConvertible.Type] = [Bool.self, Int.self, Double.self]
            func cast<T>(to: T) -> Any? { return (to.self as? LosslessStringConvertible.Type)?.init(self) }
            for type in types { if let value = cast(to: type) { return value } }
            return self
        }
    }
    
    // MARK: - URL to [URLQueryItem]
    
    extension URL {
        func toQueryItems() -> [URLQueryItem]? { return URLComponents(url: self, resolvingAgainstBaseURL: false)?.queryItems }
    }
    
    // MARK: - create [URLQueryItem] from [AnyHashable: Any] or [any]
    
    extension URLQueryItem {
        private static var _bracketsString: String { return "[]" }
        static func create(from values: [Any], with key: String) -> [URLQueryItem] {
            let _key = key.contains(_bracketsString) ? key : key + _bracketsString
            return values.compactMap { value -> URLQueryItem? in
                if value is [Any] || value is [AnyHashable: Any] { return nil }
                return URLQueryItem(name: _key, value: value as? String ?? "\(value)")
            }
        }
    
        static func create(from values: [AnyHashable: Any]) -> [URLQueryItem] {
            return values.flatMap { element -> [URLQueryItem] in
                if element.value is [AnyHashable: Any] { return [] }
                let key = element.key as? String ?? "String"
                if let values = element.value as? [Any] { return URLQueryItem.create(from: values, with: key) }
                return [URLQueryItem(name: key, value: element.value as? String ?? "\(element.value)")]
            }
        }
    }
    
     // MARK: - [AnyHashable: Any] to [URLQueryItem]
    
    extension Dictionary where Value: Any {
        func toURLQueryItems() -> [URLQueryItem] { return URLQueryItem.create(from: self) }
    }
    

    Usage

    url.toQueryItems()
    url.toQueryItems()?.toDictionary()
    
    urlString.toURLQueryItems()
    urlString.toURLQueryItems()?.toDictionary()
    
    urlQueryString?.toURLQueryItems()
    urlQueryString?.toURLQueryItems()?.toDictionary()
    
    let dictionary = ["aaa": [1234], "bbb": ["a", "b", "c"]]
    dictionary.toURLQueryItems()
    

    Full sample

    var urlString = "https://example.com/l57?condition%5B%5D=31&brand%5B%5D=289&brand%5B%5D=291&brand%5B%5D=32&year%5B%5D=23259&year%5B%5D=23757&ships_from_region%5B%5D=23684&ships_from_region%5B%5D=23683"
    let url = URL(string: urlString)!
    var urlQueryString = url.query
    
    print("URL:\n\(urlString)")
    print("URL query string:\n\(String(describing: urlQueryString))\n")
    
    print("get [URLQueryItem] from URL:\n\(String(describing: url.toQueryItems()))\n")
    print("get [String: Any] from URL:\n\(String(describing: url.toQueryItems()?.toDictionary()))\n")
    
    print("get [URLQueryItem] from url string (absoluteString):\n\(String(describing: urlString.toURLQueryItems()))\n")
    print("get [String:Any] from url string (absoluteString):\n\(String(describing: urlString.toURLQueryItems()?.toDictionary()))\n")
    
    print("get [URLQueryItem] from url string (only query):\n\(String(describing: urlQueryString?.toURLQueryItems()))\n")
    print("get [String:Any] from url string (only query):\n\(String(describing: urlQueryString?.toURLQueryItems()?.toDictionary()))\n")
    
    var dict =  [String: Any]()
    dict = ["aaa": [1234], "bbb": [1234: 22], "ccc": ["a", "b", "c"], "ffffd": [[1,2,3], [4,5,6]], "eee[]": [1,2,4], "fff": "value", "ggg": 123]
    print("Dict: \(dict)")
    print("Dict to [URLQueryItem]: \(dict.toURLQueryItems())")
    print("Dict to query oriented dictionary: \(dict.toURLQueryItems().toDictionary())")
    

    Full sample output

    URL:
    https://example.com/l57?condition%5B%5D=31&brand%5B%5D=289&brand%5B%5D=291&brand%5B%5D=32&year%5B%5D=23259&year%5B%5D=23757&ships_from_region%5B%5D=23684&ships_from_region%5B%5D=23683
    URL query string:
    Optional("condition%5B%5D=31&brand%5B%5D=289&brand%5B%5D=291&brand%5B%5D=32&year%5B%5D=23259&year%5B%5D=23757&ships_from_region%5B%5D=23684&ships_from_region%5B%5D=23683")
    
    get [URLQueryItem] from URL:
    Optional([condition[]=31, brand[]=289, brand[]=291, brand[]=32, year[]=23259, year[]=23757, ships_from_region[]=23684, ships_from_region[]=23683])
    
    get [String: Any] from URL:
    Optional(["condition": [31], "ships_from_region": [23684, 23683], "year": [23259, 23757], "brand": [289, 291, 32]])
    
    get [URLQueryItem] from url string (absoluteString):
    Optional([condition[]=31, brand[]=289, brand[]=291, brand[]=32, year[]=23259, year[]=23757, ships_from_region[]=23684, ships_from_region[]=23683])
    
    get [String:Any] from url string (absoluteString):
    Optional(["year": [23259, 23757], "ships_from_region": [23684, 23683], "condition": [31], "brand": [289, 291, 32]])
    
    get [URLQueryItem] from url string (only query):
    Optional([condition[]=31, brand[]=289, brand[]=291, brand[]=32, year[]=23259, year[]=23757, ships_from_region[]=23684, ships_from_region[]=23683])
    
    get [String:Any] from url string (only query):
    Optional(["condition": [31], "brand": [289, 291, 32], "ships_from_region": [23684, 23683], "year": [23259, 23757]])
    
    Dict: ["ccc": ["a", "b", "c"], "eee[]": [1, 2, 4], "bbb": [1234: 22], "fff": "value", "ffffd": [[1, 2, 3], [4, 5, 6]], "aaa": [1234], "ggg": 123]
    Dict to [URLQueryItem]: [ccc[]=a, ccc[]=b, ccc[]=c, ggg=123, fff=value, aaa[]=1234, eee[]=1, eee[]=2, eee[]=4]
    Dict to query oriented dictionary: ["ccc": ["a", "b", "c"], "aaa": [1234], "fff": "value", "eee": [1, 2, 4], "ggg": 123]
    
    0 讨论(0)
提交回复
热议问题