I am working with swift Alamofire, but i had an issue, i want pass data to the server but the server required escaped JSON string, like this
{\"status\":1,\"id\":\"1bcc3331b09d32f7439ad9d5f2acfb35\",\"progress\":[{\"airline_code\":\"SRI\",\"ctr\":0,\"rate\":5,\"state\":1,\"data\":null}]}
but I have this data from the response:
{"status":1,"id":"1bcc3331b09d32f7439ad9d5f2acfb35","progress":[{"airline_code":"SRI","ctr":0,"rate":5,"state":1,"data":null}]}
how can I convert JSON to escaped JSON like that,
I have tried this online converter
Converter Escape JSON
and its works perfect, how can I escape like that in swift Xcode.
update complete json (look inside feed: )
{
"flight_child":"0",
"child":"[]",
"depart_hidden_transit":"0",
"depart_adult_surcharge":"0",
"depart_flight":"[{\"airlineCode\":\"LIO\",\"arriveCity\":\"Jakarta Soekarno Hatta\",\"arriveDate\":\"2018-04-28\",\"arriveDatetime\":\"2018-04-28 20:05\",\"arrivePort\":\"CGK\",\"arriveTime\":\"20:05\",\"arriveTimezone\":7.0,\"departCity\":\"Yogyakarta\",\"departDate\":\"2018-04-28\",\"departDatetime\":\"2018-04-28 18:50\",\"departPort\":\"JOG\",\"departTime\":\"18:50\",\"departTimezone\":7.0,\"flightNumber\":\"JT 555\",\"stopCount\":0}]",
"auth_mode":"",
"flight_infant":"0",
"flight_to":"CGK",
"flight_return":"",
"depart_child_discount":"0",
"infant":"[]",
"depart_choice":"d3ea46551c769f462c3e1a4dd25c933d",
"depart_child_surcharge":"0",
"version_code":"3",
"contact_email":"mul#gmai.oc",
"contact_name":"Mulia RIfai",
"adult":"[[\"Mr\",\"Muhammad Fuad\",null,null,\"0\",null,null,null,null,null]]",
"flight_trip":"oneway",
"flight_adult":"1",
"depart_adult_discount":"0",
"contact_phone":"0972312",
"depart_carrier":"LIO",
"client_password":"arena123",
"depart_infant_discount":"0",
"depart_infant_surcharge":"0",
"client_username":"androidarena",
"flight_depart":"2018-05-03",
"feed":"{\"status\":1,\"id\":\"1bcc3331b09d32f7439ad9d5f2acfb35\",\"progress\":[{\"airline_code\":\"SRI\",\"ctr\":0,\"rate\":5,\"state\":1,\"data\":null}]}",
"contact_title":"Mr.",
"flight_from":"JOG",
"depart_class":"eco",
"device_id":"123456789011123"
}
Even though this should be fixed by the server. A nasty hack would be to first stringify your json that should be passed as the string and then replacing the occurrence of double quotation with \".
let dic = ["status":1,
"id":"1bcc3331b09d32f7439ad9d5f2acfb35",
"progress":[["airline_code":"SRI","ctr":0,"rate":5,"state":1,"data":nil]
]
] as [String : Any]
if let json = try? JSONSerialization.data(withJSONObject: dic, options: JSONSerialization.WritingOptions.init(rawValue: 0)) {
if let str = String(data: json, encoding: String.Encoding.utf8)?.replacingOccurrences(of: "\"", with: "\\\"") {
print(str)
}
}
Result:
{\"id\":\"1bcc3331b09d32f7439ad9d5f2acfb35\",\"status\":1,\"progress\":[{\"state\":1,\"airline_code\":\"SRI\",\"data\":null,\"ctr\":0,\"rate\":5}]}
Related
I have encoded a Codable object:
let encodedData = try JSONEncoder().encode(someObject)
And I print the JSON by doing the following (I know its not safe, I'm just testing):
let json = try! JSONSerialization.jsonObject(with: encodedData)
print("JSON: \(json)")
My JSON has lots of spaces. I want a way to remove these spaces, to save space on the encoded String. You can tell that it looks quite different from a normal JSON due to these spaces.
JSON (part of it):
How can I reduce the spaces to reduce the bytes this takes up?
As #Martin R pointed out, I was not printing the JSON properly. It should have instead been:
let jsonString = String(data: encodedData, encoding: .utf8)!
print(jsonString)
The result looks like so:
{"type":1,"modifiers":[],"parameters":{ ...
This printed data can then be decoded in the future like so:
let data = Data(jsonString.utf8)
let someResult = try JSONDecoder().decode(SomeType.self, from: data)
I'm attempting to print out a string array without escaped single quotes. For some reason, Swift is injecting escaped single quotes when printing my array. This has a trickle down problem when I use the array to build JSON. JSON ends up not being able to parse due to the escaped single quotes.
I thought this was a problem with my code, but I've distilled this down to a single usecase that should be straightforward.
let names = ["Tommy 'Tiny' Lister", "Tom Hanks"]
print(names)
The output is:
["Tommy \'Tiny\' Lister", "Tom Hanks"]
Note: I did not include escaped single quotes in my names array.
How do I prevent this from happening?
Here is the what I'm doing later in code to create JSON. For purposes of brevity, this is a really dumbed down version of what I'm doing:
var names = ["Tommy Tiny Lister", "Tom Hanks"]
var jsonString = """
{"names": \(names)}
"""
var jsonData = jsonString.data(using: .utf8)
if let json = try? JSONSerialization.jsonObject(with: jsonData!) as? [String: Any] {
let jsonData = try! JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
let string = String(data: jsonData, encoding: .utf8)
print(string!)
}
What you are doing is using Swift arrays' description to generate JSON:
var jsonString = """
{"names": \(names)}
""" // your JSON will contain name.description
You are relying on the fact that the implementation of description just so happens to result in the same format as JSON most of the time. As you can see, when there are ' in the array elements, the description is not valid JSON.
Basically, you should not rely on the description to generate JSON. Instead, you should use Codable to generate JSON data from a Swift array.
For the JSON you want to produce:
{
"names": ["Tommy 'Tiny' Lister", "Tom Hanks"]
}
You can use a struct like this:
struct Names : Codable {
let names: [String]
}
And then you can produce JSON Data like this:
let encoder = JSONEncoder()
do {
let obj = Names(names: ["Tommy 'Tiny' Lister", "Tom Hanks"])
let data = try encoder.encode(obj)
} catch { ... }
Let's say there's a JSON-string I got from server: "\"3\"" (with quotes, i.e. length == 3 here)
In Android-world, I can do:
gson.fromJson(json, new TypeToken<String>() {}.getType()); - it returns "3" (i.e. length == 1)
In C#-world, can use NewtonSoft.Json:
JsonConvert.DeserializeObject<string>(json, settings) - it returns "3" (i.e. length == 1)
And other way around, I do have string I want to serialize as a JSON.
In Android I'd do gson.toJson("\"3\"") and in C# - JsonConvert.SerializeObject("\"3\"")
The problem with JSONSerialization is that it doesn't treat plain string as a valid JSON: JSONSerialization.isValidJSONObject("\"3\"") == *false*
What would be equivalent in Swift / Obj-C world?
The ugly workaround I've found (except of just adding/removing quotes) so far is to wrap string into 1-item-array to make JSONSerialization happy and then remove "[","]" from resulted JSON-string (and other way around - add "[", "]" before deserialization), but it's a way too disgusting to be the real solution for this problem.
When de-serializing JSON which does not have an array or
dictionary as top-level object you can pass the
.allowFragments option:
let jsonString = "\"3\""
let jsonData = jsonString.data(using: .utf8)!
let json = try! JSONSerialization.jsonObject(with: jsonData, options: .allowFragments)
if let str = json as? String {
print(str) // 3
}
However, there seems to be no way to serialize a plain string to JSON
with the JSONSerialization class from the Foundation library.
Note that according to the JSON specification,
a JSON object is a collection of name/value pairs (dictionary) or
an ordered list of values (array). A single string is not a valid
JSON object.
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 wrong with this piece of code (which was inspired by this example)? It currently prints JSON string "(<5b5d>, 4)" instead of the expected "[]".
var tags: [[String]] = []
// tags to be added later ...
do {
let data = try NSJSONSerialization.dataWithJSONObject(tags, options: [])
let json = String(data: data, encoding: NSUTF8StringEncoding)
print("\(json)")
}
catch {
fatalError("\(error)")
}
Short answer: The creation of the JSON data is correct. The problem is in the
conversion of the data to a string, what you want is the NSString method:
let json = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
which produces the expected [].
Slightly longer answer:
Your code
let json = String(data: data, encoding: NSUTF8StringEncoding)
calls the String init method
/// Initialize `self` with the textual representation of `instance`.
/// ...
init<T>(_ instance: T)
and the result is the textual representation of the tuple
(data: data, encoding: NSUTF8StringEncoding):
(<5b5d>, 4)
Actually you can call String() with arbitrary arguments
let s = String(foo: 1, bar: "baz")
print(s) // (1, "baz")
in Swift 2. This does not compile in Swift 1.2, so I am not sure if
this is intended or not. I have posted a question in the
Apple Developer Forums about that:
String init accepts arbitrary arguments.