Swift: Get all key value pairs from a String - ios

I have a String which has many key value pairs appended by a & sign. i.e: params = key1=Hello&key2=Hello World&key3=Hi Hello
Is there a way to extract the values just by passing the keys present in the string? For example I want to extract the value of key1, key2, key3.

let string = "key1=Hello&key2=Hello World&key3=Hi Hello"
let components = string.components(separatedBy: "&")
var dictionary: [String : String] = [:]
for component in components{
let pair = component.components(separatedBy: "=")
dictionary[pair[0]] = pair[1]
}
And in dictionary you will get your key-value pairs.

You can use URLComponents and URLQueryItem anyway by creating a dummy URL
let params = "key1=Hello&key2=Hello World&key3=Hi Hello"
if let components = URLComponents(string: "http://dummy.com/path?" + params.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!),
let queryItems = components.queryItems {
let arrayOfValues = queryItems.flatMap{ $0.value }
print(arrayOfValues)
}
see also Best way to parse URL string to get values for keys?

let params = "key1=Hello&key2=Hello World&key3=Hi Hello"
let sepparated = params.components(separatedBy: CharacterSet(charactersIn: "&="))
let keys = sepparated.enumerated().filter{$0.0 % 2 == 0}
print (keys) // [(offset: 0, element: "key1"), (offset: 2, element: "key2"), (offset: 4, element: "key3")]

Related

Get correct parameter value from URL in "/:id=" format using regex

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.
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))
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.
You can use next regex approach to enumerate parameters in your url path:
let urlString = "urlScheme://search/:id=0001" as NSString
let regex = try! NSRegularExpression(pattern: "([^:\\/]+)=([0-9]+)")
if let match = regex.matches(in: urlString as String, options: [], range: NSMakeRange(0, urlString.length)).first, match.numberOfRanges == 3 {
let key = urlString.substring(with: match.range(at: 1))
let value = urlString.substring(with: match.range(at: 2))
print(key, ":", value)
}
// Prints
id : 0001

can i sum of values that has the same key in dictionary

I have a dictionary like this :
let dic: KeyValuePairs = ["foo":2,"bar":3,"bat":5, "foo":5,"bat":7,"bar":5]
I want the sum of values that has the same key.
The output should look like this:
["foo":7, "bar":8, "bat":12]
KeyValuePairs responds to reduce so you can do this
let dic: KeyValuePairs = ["foo":2,"bar":3,"bat":5, "foo":5,"bat":7,"bar":5]
let result : [String:Int] = dic.reduce(into: [:]) { (current, new) in
current[new.key] = new.value + (current[new.key] ?? 0)
}

How to get data from string after particular backslash?

I have a string such as \home\var\path\uplaod\abc.png. Now I want to get data from uplaod onwards. Please suggest any function or code?
If path of image is not fixed or order of uplaod is not specific try like this.
let string = "\\home\\var\\path\\uplaod\\abc.png"
if let range = string.range(of: "uplaod") {
let imagePath = string.substring(from: range.lowerBound)
print(imagePath)
}
Output
uplaod\abc.png
let string = "\\home\\var\\path\\uplaod\\abc.png"
let parts = string.components(separatedBy: "\\")
parts // ["", "home", "var", "path", "uplaod", "abc.png"]
Any of the elements of this array you can get by its index.
parts[4..<parts.count].joined(separator: "\\") // "uplaod\\abc.png"

Convert String Array to JSON or 2D Array SWIFT

I currently have a NSMutableArray "localArray" and I am trying to create that into a JSON Array or a 2D Array. I get this data my creating a database and running a query using a for loop on the database.
{
Food,
Burger,
3.99,
1.25,
POP,
Crush,
1.99,
.89,
and more.
}
The reason why I am looking for a JSON or 2d Array is I want to hold the data in the localArray in such a way that I can identify by type and then do something like .valueForKey("Name") or .valurForKey("Price") and add that to my tableview's cell text label or labels.
{
{
Type Food,
Name Burger,
Price 3.99,
Cost 1.25,
},
{
Type POP,
Name Crush,
Price 1.99,
Cost .89,
},
and more
}
I have already tried JSONSerialization, but that failed and also tried 2d Array but no luck.
Any help will be highly appreciated.
This is how I Query and add the data to localArray
let queryType = data.select(ada, code, name, proof, size, case_size, price)
.filter(bevType == type)
let rows = Array(queryType)
for row in rows{
let name = row[self.name]
let type = row[self.type]
let cost = row[self.cost]
let price = row[self.price]
localArray.addObject(name)
localArray.addObject(type)
localArray.addObject(cost)
localArray.addObject(price)
}
I solved it myself by creating a dictionary.
for row in rows{
var rDict: Dictionary = [String: String]()
rDict["Name"] = row[self.name]
rDict["Type"] = row[self.type]
rDict["Cost"] = row[self.cost]
rDict["Price"] = row[self.price]
localArray.addObject(rDict)
}
If fields are always repeating in count of 4, you can try doing this:
var array = [[String: AnyObject]]()
for var i = 0 ; i < array.count ; i += 4 {
var k = 0
var dict = [String: AnyObject]
dict["Type"] = array[i + k++]
dict["Name"] = array[i + k++]
dict["Price"] = array[i + k++]
dict["Cost"] = array[i + k]
array.append(dict)
}
Then extract dictionary from this swift array and use same keys to extract data from dictionary to be used in your cell like
let dict = array[indexPath.row]
cell.title = dict["Name"]

How to unwrap NSMutableDictionary.allkeys in optional String Array

I am trying to get all the key values of NSMutableDictionary as String Array. I am using this myNSMutableDictionary.allkeys to get the values as an Array but I cannot find a way to unwrap the key values.
This is what I have tried so far:
for (key, _) in NSMutableDictionary {
println("THIS IS MY NEW KEY\(key)")
}
And I tried this
var myArray:NSArray = myNSMutableDictionary.allKeys
var string:NSString? = uniqueIDArray[0] as? NSString
println("This is unwraped value\(string!)")
And this
var myArray:Array = myNSMutableDictionary.allKeys
println("This is unwraped value\(myArray[0])")
I keep getting the value as Optional("kMSZgoTmiX") instead of kMSZgoTmiX which is the key value I need
Thank you for all your help!
So you've got a dictionary with values that are strings (and keys that are something, assume String):
var dictionaryOfStringValues : [String:String] = /* your dictionary */
And you want to iterate over the contents:
for (key, val) in dictionaryOfStringValues {
// use key and val
}
If you just want the values in a way you can easily iterate over:
var theValues = dictionaryOfStringValues.values
If you insist that theValues be an Array:
var theValuesAsAnArray = Array(dictionaryOfStringValues.values)
If you are starting with an NSMutableDictionary, then convert it at the point where it FIRST ENTERS your Swift code into a Swift Dictionary. Use an as variant to do that. After that, pure Swift.
Like this:
7> for (key, value) in ["a":1, "b":2] {
8. println (key)
9. println (value)
10. }
b
2
a
1
let myNSMutableDictionary = NSMutableDictionary()
myNSMutableDictionary["myKey1"] = 5
myNSMutableDictionary["myKey2"] = 10
myNSMutableDictionary["myKey3"] = 15
let myKeysArrayUnsorted = myNSMutableDictionary.allKeys as [String]
let myValuesArrayUnsorted = myNSMutableDictionary.allValues as [Int]
let keyString = myKeysArrayUnsorted[0] // "myKey2"
let keyValue = myNSMutableDictionary[keyString] as Int // 10
println("This is my first unsorted key \(keyString) = \(keyValue)")
let myKeysArraySorted = (myNSMutableDictionary.allKeys as [String]).sorted(<)
for key in myKeysArraySorted {
println(myNSMutableDictionary[key]!) // 5 10 15
}

Resources