Swift: Change JSON formatted NSURLRequest to String - ios

What I am doing is shipping a JSON structured string on NSULRRequest, getting rid of the urlscheme prefix, serialize it to JSON and then whatever I can do with it.
urlscheme://{"Type":"photo","Name":"Photo13"}
So I changed NSURLRequest to string by doing
let url = request.URL
let string = "\(url)"
print(string)
but the string appears like
urlscheme://%7B%22Type%22:%22photo%22,%22Name%22:%22Photo13%22%7D
So I have to change it by invoking stringByReplacingOccurrencesOfString over and over on all possible changes.
replacedString = replacedString.stringByReplacingOccurrencesOfString("%7B",
withString: "{",
options: NSStringCompareOptions.LiteralSearch,
range: nil)
.
..
...
Is there a better way to do this in Swift?

What you've got there is a percent encode string. This is done because certain characters have special meanings within a URL. The NSString method stringByRemovingPercentEncoding will convert a percent encode string back to a normal string for you.
See this answer

Related

Swift URL decoding does not decode string

when trying to decode the following encoded string, it does not work...it´s actually doing nothing...leaving the string as it is:
https://www.foodhat.app/?rOpeningTime=08:00&rClosingTime=20:00&rClosedUntil=2019-08-19&pId=557&rId=69&goTo=CUSTOMER_PRODUCT_DETAILS&cName=Duhok&pName=%D9%85%D9%86%D8%B3%D9%81+%D8%AF%D9%88%D9%84%D9%85%D8%A9&rName=Mansaf+Alzain&rMinOrderValue=15000
pName is arabic, so do not wonder the encoding of it.
I use str.removingPercentEncoding to decode the string...but as said...it doesn´t remove the "+" (e.g. in rName)!
Result is
let str = "https://www.foodhat.app/?rOpeningTime=08:00&rClosingTime=20:00&rClosedUntil=2019-08-19&pId=557&rId=69&goTo=CUSTOMER_PRODUCT_DETAILS&cName=Duhok&pName=%D9%85%D9%86%D8%B3%D9%81+%D8%AF%D9%88%D9%84%D9%85%D8%A9&rName=Mansaf+Alzain&rMinOrderValue=15000"
print(str.removingPercentEncoding!)
//https://www.foodhat.app/?rOpeningTime=08:00&rClosingTime=20:00&rClosedUntil=2019-08-19&pId=557&rId=69&goTo=CUSTOMER_PRODUCT_DETAILS&cName=Duhok&pName=منسف+دولمة&rName=Mansaf+Alzain&rMinOrderValue=15000
What am I doing wrong?
Use 'str.replacingOccurrences()' instead. A better solution would be to use 'URLComponents', 'queryItems' to perform the filtering on the targeted queryItem, to ensure that '+' removal is not done for the entire url.
When decoding an URL you should use URLComponents :
let url = URL(string:"https://www.foodhat.app/?rOpeningTime=08:00&rClosingTime=20:00&rClosedUntil=2019-08-19&pId=557&rId=69&goTo=CUSTOMER_PRODUCT_DETAILS&cName=Duhok&pName=%D9%85%D9%86%D8%B3%D9%81+%D8%AF%D9%88%D9%84%D9%85%D8%A9&rName=Mansaf+Alzain&rMinOrderValue=15000")!
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
print(components)
Output is :
[rOpeningTime=08:00, rClosingTime=20:00, rClosedUntil=2019-08-19, pId=557, rId=69, goTo=CUSTOMER_PRODUCT_DETAILS, cName=Duhok, pName=منسف+دولمة, rName=Mansaf+Alzain, rMinOrderValue=15000]

Swift URL.path changes encoding of utf-8 characters

Why does converting a String to an URL in Swift 4.2 and then converting the URL back to a String using url.path change the encoding of special characters like german umlauts (ä, ö, ü), even if I use a utf-8 encoding?
I wrote some sample code to show my problem. I encoded the strings to base64 in order to show that there is a difference.
I also have a similar unsolved problem with special characters and swift here.
Sample Code
let string = "/path/to/file"
let stringUmlauts = "/path/to/file/with/umlauts/testäöü"
let base64 = Data(string.utf8).base64EncodedString()
let base64Umlauts = Data(stringUmlauts.utf8).base64EncodedString()
print(base64, base64Umlauts)
let url = URL(fileURLWithPath: string)
let urlUmlauts = URL(fileURLWithPath: stringUmlauts)
let base64Url = Data(url.path.utf8).base64EncodedString()
let base64UrlUmlauts = Data(urlUmlauts.path.utf8).base64EncodedString()
print(base64Url, base64UrlUmlauts)
Output
The base64 and base64Url string stay the same but the base64Umlauts and the base64UrlUmlauts are different.
"L3BhdGgvdG8vZmlsZQ==" for base64
"L3BhdGgvdG8vZmlsZQ==" for base64Url
"L3BhdGgvdG8vZmlsZS93aXRoL3VtbGF1dHMvdGVzdMOkw7bDvA==" for base64Umlauts
"L3BhdGgvdG8vZmlsZS93aXRoL3VtbGF1dHMvdGVzdGHMiG/MiHXMiA==" for base64UrlUmlauts
When I put the base64Umlauts and base64UrlUmlauts strings into an online Base64 decoder, they both show /path/to/file/with/umlauts/testäöü, but the ä, ö, ü are different (not visually).
stringUmlauts.utf8 uses the Unicode characters äöü.
But urlUmlauts.path.utf8 uses the Unicode characters aou each followed by the combining ¨.
This is why you get different base64 encoding - the characters look the same but are actually encoded differently.
What's really interesting is that Array(stringUmlauts) and Array(urlUmlauts.path) are the same. The difference doesn't appear until you perform the UTF-8 encoding of the otherwise exact same String values.
Since the base64 encoding is irrelevant, here's a more concise test:
let stringUmlauts = "/path/to/file/with/umlauts/testäöü"
let urlUmlauts = URL(fileURLWithPath: stringUmlauts)
print(stringUmlauts, urlUmlauts.path) // Show the same
let rawStr = stringUmlauts
let urlStr = urlUmlauts.path
print(rawStr == urlStr) // true
print(Array(rawStr) == Array(urlStr)) // true
print(Array(rawStr.utf8) == Array(urlStr.utf8)) // false!!!
So how is the UTF-8 encoding of two equal strings different?
One solution to this is to use precomposedStringWithCanonicalMapping on the result of path.
let urlStr = urlUmlauts.path.precomposedStringWithCanonicalMapping
Now you get true from:
print(Array(rawStr.utf8) == Array(urlStr.utf8)) // now true

Converting string (Contains json string) to NSURL in swift

I have PAI its Implemented in .NET.
one of the web service url is like this
http://123.321.33/UploadCitizenImage?jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}
while converting above string to URL in swift, app going crash.
for more info check this
The URL(string:) initializer returns an optional since the parsing of the string may fail. In that case, nil is returned. That's exactly what's happening here since the string you are providing is not a valid URL: there are several characters in the query that are not allowed there and need to be replaced: { as %7B, " as %22, space as %20 and } as %7D.
So the initializer returns nil. Next thing you do is force unwrap via the ! operator. But force-unwrapping a nil is illegal and is why you get the crash.
If you want to create an URL, please look into the URLComponents class which does all the necessary escaping for you so you don't need to care about it. The queryItems property is of particular interest for you, it's an array of URLQueryItem.
Please do something like that,
let jsonString = "jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}" as String
let urlEncoadedJson = jsonString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
let urls = NSURL(string:"http://123.321.33/UploadCitizenImage?\(urlEncoadedJson ?? "")")
First convert your json into encodedJson then add into your url.
Do let me know if there is some issue.
You can try this,
let string = "http://123.321.33/UploadCitizenImage?jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}"
let escapedString = string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let url = URL(string: escapedString!)!
print(url)
Output will be like this,
http://123.321.33/UploadCitizenImage?jsonString=%7B%22Mobile%22:%2212345678%22,%20%22fileName%22:%227661832460_05072018.png%22%7D

I receive an improperly formatted unicode in a String

I am working with a web API that gives me strings like the following:
"Eat pok\u00e9."
Xcode complains that
Expected Hexadecimal code in braces after unicode escape
My understanding is that it should be converted to pok\u{00e9}, but I do not know how to achieve this.
Can anybody point me in the right direction for me develop a way of converting these as there are many in this API?
Bonus:
I also need to remove \n from the strings.
You may want to give us more context regarding what the raw server payload looked like, and show us how you're displaying the string. Some ways of examining strings in the debugger (or if you're looking at raw JSON) will show you escape strings, but if you use the string in the app, you'll see the actual Unicode character.
I wonder if you're just looking at raw JSON.
For example, I passed the JSON, {"foo": "Eat pok\u00e9."} to the following code:
let jsonString = String(data: data, encoding: NSUTF8StringEncoding)!
print(jsonString)
let dictionary = try! NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: String]
print(dictionary["foo"]!)
And it output:
{"foo": "Eat pok\u00e9."}
Eat poké.
By the way, this standard JSON escape syntax should not be confused with Swift's string literal escape syntax, in which the hex sequence must be wrapped in braces:
print("Eat pok\u{00e9}.")
Swift uses a different escape syntax in their string literals, and it should not be confused with that employed by formats like JSON.
#Rob has an excellent solution for the server passing invalid Swift String literals.
If you need to convert "Eat pok\u00e9.\n" to Eat poké it can be done as follows with Swift 3 regex.
var input = "Eat pok\\u00e9.\n"
// removes newline
input = String(input.characters.map {
$0 == "\n" ? " " : $0
})
// regex helper function for sanity's sake
func regexGroup(for regex: String!, in text: String!) -> String {
do {
let regex = try RegularExpression(pattern: regex, options: [])
let nsString = NSString(string: text)
let results = regex.matches(in: text, options: [], range: NSMakeRange(0, nsString.length))
let group = nsString.substring(with: results[0].range)
return group
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
return ""
}
}
let unicodeHexStr = regexGroup(for:"0\\w*", in: input)
let unicodeHex = Int(unicodeHexStr, radix: 16)!
let char = Character(UnicodeScalar(unicodeHex)!)
let replaced = input.stringByReplacingOccurrencesOfString("\\u"+unicodeHexStr, withString: String(char))
// prints "Eat poké"
print(replaced)
\u{00e9} is a formatting that's specific to Swift String literals. When the code is compiled, this notation is parsed and converted into the actual Unicode Scalar it represents.
What you've received is a String that escapes Unicode scalars in a particlar way. Transform those escaped Unicode Scalars into the Unicode Scalars they represent, see this answer.

What is the iOS proper URL encoding of "+" character?

Is there seriously not a way natively to URL Encode the value of a query string parameter that has a "+" character in it?
e.g.
me+blah#domain.net
to
me%2Bblah%40#domain.net?
I tried solutions like posted in these other questions, but those do not properly encode that email.
Swift - encode URL
How do I URL encode a string
A swift solution would be preferred as that is what I am working in at the moment, but I am capable of translating Objective-C Code to swift code for the most part.
Specifically I am trying to x-www-form-urlencoded encode query string values in the body of POST request.
let email = "me+blah#domain.net"
let output = CFURLCreateStringByAddingPercentEscapes(nil, email as NSString, nil, ":/?#!$&'()*+,;=" as NSString, CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding))
// output = "me%2Bblah%40domain.net"
CFURLCreateStringByAddingPercentEscapes doesn't escape + or # by default, but you can specify it (as I did along with other characters, in the ":/?#!$&'()*+,;=" string).
Edit: If you want output to be a Swift string:
let output = (CFURLCreateStringByAddingPercentEscapes(nil, email as NSString, nil, ":/?#!$&'()*+,;=" as NSString, CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) as NSString) as String
println(("me+blah#domain.net" as NSString)
.stringByAddingPercentEncodingWithAllowedCharacters(
NSCharacterSet.alphanumericCharacterSet()))
Output:
Optional("me%2Bblah%40domain%2Enet")
In Objective-C:
NSString *encodedString =
["me+blah#domain.net" stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet alphanumericCharacterSet]];

Resources