What is the best way to get the id value from this url:
URL(string: "urlScheme://search/:id=0001")
I've been trying to route this URL using a deep link request. However, my url routing solution JLRoutes shows the parameters as key = id and value = :id=0001.
I instead need the parameters to be key = id and value = "0001".
In an ideal world I would just be using a URL string like "urlScheme://search/0001" and not have any problem but the ":id=" part has to be in there. George's comment about converting the parameter to a URL in of itself and using .pathComponents.last does work, but I think a regex solution is probably going to scale better going forward.
CodePudding user response:
If your URL is in the form of an actual URL query, e.g. urlScheme://search?id=0001
, there is a nice way to do this.
With thanks to vadian, this is really simple. You can just do the following:
let components = URLComponents(string: "urlScheme://search?id=0001&a=2")!
let dict = components.queryItems?.reduce(into: [:]) { partialResult, queryItem in
partialResult[queryItem.name] = queryItem.value
}
Or a slightly more compact version for dict
:
let dict = components.queryItems?.reduce(into: [:], { $0[$1.name] = $1.value })
Result from given input:
["id": "0001", "a": "2"]
If you must use the current URL form
You can replace the URL string, such as:
let urlStr = "urlScheme://search/:id=0001/:a=2"
let comps = urlStr.components(separatedBy: "/:")
let newUrl: String
if comps.count > 1 {
newUrl = "\(comps.first!)?\(comps.dropFirst().joined(separator: "&"))"
} else {
newUrl = urlStr
}
print(newUrl)
Prints: urlScheme://search?id=0001&a=2
Original answer (slightly modified)
If you have a URL with queries separated by /:
you can use the following:
// Example with multiple queries
let url = URL(string: "urlScheme://search/:id=0001/:a=2")!
let queries = url.lastPathComponent.dropFirst().split(separator: "/:")
var dict = [String: String]()
for query in queries {
let splitQuery = query.split(separator: "=")
guard splitQuery.count == 2 else { continue }
let key = String(splitQuery.first!)
let value = String(splitQuery[1])
dict[key] = value
}
print(dict)
Result is same as before.
CodePudding user response:
The answer from @George should work fine, but two things struck me: you decided you wanted a regex solution, and to make this generic seemed to be asking for a recursive solution.
The below approach uses regex to identify up to the last /:
delimiter, then has to do a bit of inelegant string handling to split it into the base string and the final pair of (key: value) params. I'd hoped to be able to write a regex that just matches those final parameters as that would be a far cleaner range to work with, but haven't managed it yet!
func paramsFrom(_ str: String) -> [String: String] {
guard let baseRange = str.range(of:#"^. \/:"#, options: .regularExpression ) else { return [:] }
let base = String(str[baseRange].dropLast(2))
let params = str.replacingCharacters(in: baseRange, with: "").components(separatedBy: "=")
return [params.first! : params.last!].merging(paramsFrom(base)){(current, _) in current}
}
using this on your example string returns:
["id": "0001", "title": "256", "count": "100"]
EDIT:
Managed to dig out the old regex brain cells and match just the final pair of parameters. You could adapt the above to use the regex
(?<=\/:)[a-zA-Z0-9=] $
and the have slightly cleaner string handling as the shortened base string becomes
String(str.dropLast(str[paramsRange].count))