如何在 Swift 中将 url.query 转换为字典?

问题描述 投票:0回答:7

我有一个 URL 进入 AppDelegate 方法:

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

网址看起来像

www.wesite.com/shareplace.html?placeid=123

如何转换成字典方便查阅?

我在一些网站上找到了一些代码,但它在 Xcode 9 中显示错误:

 extension URL {
    var queryDictionary: [String: AnyObject]? {
        return URLComponents(url: self, resolvingAgainstBaseURL: false)?
            .queryItems?
            .reduce([:], combine: { (var result: [String: AnyObject], queryItem) -> [String: AnyObject] in
                if queryItem.value?.containsString(",") ?? false {
                    let array = queryItem.value?.componentsSeparatedByString(",")

                    result[queryItem.name] = array
                }
                else {
                    result[queryItem.name] = queryItem.value
                }

                return result
            })
    }
}

.reduce([:], combine: { (var result: [String: AnyObject], queryItem)
  -> [String: AnyObject] in
(var 结果)参数可能没有 'var' 说明符

ios swift nsdictionary nsurl
7个回答
22
投票

简单扩展

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
    }
}

使用

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")

13
投票

这是一个使用 Swift reduce 函数的示例。这会将像 'key1=value1&key2=value2&key3=value3' 这样的字符串变成字典。

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]
    }
}

8
投票

详情

  • 斯威夫特5
  • Xcode 版本 10.2.1 (10E1001)

解决方案

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) }
}

使用方法

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()

完整样本

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"], "ddd": [[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())")

完整样本输出

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", "ddd": [[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]

1
投票

斯威夫特5.5.3

extension URL {
    
    var getQueries: [String: String] {
        var dict: [String:String] = [:]
        let items = URLComponents(string: absoluteString)?.queryItems ?? []
        items.forEach { dict.updateValue($0.value ?? "", forKey: $0.name) }
        return dict
    }
}

希望有帮助!


0
投票

使用.first(其中:)

        guard let query = components.queryItems else {
            return
        }
        
        guard let accessToken = query.first(where: { $0.name == "access_token" }) else {
            return
        }

0
投票

我喜欢这种方法,其中

[URLQueryItem]
本身得到了扩展。

extension Array where Element == URLQueryItem {
    var queryDictionary: [String: Any] {
        self.reduce(into: [:]) {
            params, queryItem in
            params[queryItem.name] = queryItem.value
        }
    }
}

可以这样使用:

let urlComponents = URLComponents(string: url.absoluteString)
let queryDictionary = urlComponents.queryItems?.queryDictionary ?? [:]

-1
投票

也可以试试这个:

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
            })
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.