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

问题描述 投票:5回答:5

我有一个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 result)参数可能没有'var'说明符

ios swift nsdictionary nsurl
5个回答
12
投票

简单的扩展

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

5
投票

以下是使用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]
    }
}

2
投票

细节

  • 斯威夫特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? [String] ?? []
                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(["brand": [32], "ships_from_region": [23683], "year": [23757], "condition": [31]])

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": [23757], "condition": [31], "brand": [32], "ships_from_region": [23683]])

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(["brand": [32], "year": [23757], "condition": [31], "ships_from_region": [23683]])

Dict: ["ggg": 123, "ddd": [[1, 2, 3], [4, 5, 6]], "fff": "value", "aaa": [1234], "bbb": [1234: 22], "ccc": ["a", "b", "c"], "eee[]": [1, 2, 4]]
Dict to [URLQueryItem]: [ggg=123, eee[]=1, eee[]=2, eee[]=4, ccc[]=a, ccc[]=b, ccc[]=c, fff=value, aaa[]=1234]
Dict to query oriented dictionary: ["ggg": 123, "fff": "value", "ccc": ["a", "b", "c"], "aaa": [1234], "eee": [4]]

0
投票

试试这个:

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
投票

使用:

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