This question already has answers here:
Simple and clean way to convert JSON string to Object in Swift
(17 answers)
Closed 5 years ago.
I got JSON file from API but the content looks like this:
[
"https:\/\/seekingalpha.com\/article\/4125943-apple-homepod-delay-big-deal?source=feed_symbol_AAPL"
]
Suppose the JSON Object above is named as json. Then I just convert the object to string using String() method.
strings = String(json)
When I changed it to String type, it seems to get unnecessary '\n' and whitespace in it.
"[\n \"https:\\/\\/seekingalpha.com\\/article\\/4125943-apple-homepod-delay-big-deal?source=feed_symbol_AAPL\"\n]"
So it seems like the content of the JSON file is:
["\n""whitespace""whitespace""String""\n"]
When I changed it to String type, Swift just treats all the elements in it as a whole and wrapped it as a string.
My question is, how to extract the String inside so it looks like:
"https:\\/\\/seekingalpha.com\\/article\\/4125943-apple-homepod-delay-big-deal?source=feed_symbol_AAPL\"
As I am not so familiar with Swift so how to extract String or JSON Object is not easy for me. Any hints or help will be appreciated.
Swift 3,4 :
The given JSON format is Array of String.
if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String]{
let firstElement = json?.first ?? "Element Not Found!"
print(firstElement)
}
Swift 4:
if let json = try? JSONDecoder().decode(Array<String>.self, from: data){
let firstElement = json.first ?? "First Element Not Found!"
print(firstElement)
}
Note:
If your the Array contains more than one String. Here,urls is the class variable. i.e.,var urls = [String]()
Swift 3,4 :
if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String]{
if json != nil{
self.urls = json!
}
print(self.urls)
}
Swift 4:
if let json = try? JSONDecoder().decode(Array<String>.self, from: data){
self.urls = json
}
1. You will first have to convert JSON to Data
2. Convert data to string wrt to encoding
func jsonToString(jsonTOConvert: AnyObject){
do {
let data = try JSONSerialization.data(withJSONObject: jsonTOConvert, options: JSONSerialization.WritingOptions.prettyPrinted)
let convertedString = String(data: data, encoding: String.Encoding.utf8)
} catch let myJSONError {
print(myJSONError)
}
}
You are asking that a String be created with the contents:
[
"https:\/\/seekingalpha.com\/article\/4125943-apple-homepod-delay-big-deal?source=feed_symbol_AAPL"
]
The string object is doing exactly what you told it to — the thing you've asked it to represent begins with a square bracket, then there's a line break, then two spaces, etc, so the string contains a square bracket, then a line break, then two spaces, etc. There is no 'unnecessary' \n, there is only the \n you told it to put in.
If you obtained a JSON object then you need to parse it as JSON. JSONSerialization will do that job. What you've actually got is an array with a single item, which is a string. So JSONSerialization will return an array. The first item of that should be a string that is the seekingalpha.com URL.
Related
I’m getting a bunch of unneeded “escaped back-slash” characters when I convert my Swift Dictionary object using JSONSerialization. It’s only happening on one of my Key-Value pairs - the one that has a URL in it:
"image" : "http:\/\/www.someWebSite.com\/images/\triangleImage.jpg”
I tried to run JSONSerialization twice thinking it might solve the problem - but it just crashes. Swift is not my main language so I’m not really sure how to fix this?
Here’s my code:
// Creating the Dictionary:
triangleDictionary["name"] = "triangle 01”
triangleDictionary["image"] = "http://www.someWebSite.com/triangleImage.jpg"
triangleDictionary["description"] = "a geometric shape"
// Serializing it to a JSON object:
do {
let triangleData = try JSONSerialization.data(withJSONObject: triangleDictionary, options: [.prettyPrinted])
let triangleDataJSONString = String(data: triangleData, encoding: .utf8)!
print("triangleDataJSONString = \(String(describing: triangleDataJSONString))")
}
catch {
print("ERROR Serializing triangleData!: \(error)")
}
The output I get is almost perfect - except for those extra back-slashes:
{
"name" : “triangle 01”,
"description" : “a geometric shape”,
"image" : "http:\/\/www.someWebSite.com\/images/\triangleImage.jpg”
}
What do I need to do to fix this?
Add this line in your code
header('Content-Type: application/json');
i try to put a json in a dictionary to send that dictionary to server using alamofire
i make json string but when i put it in a dictionary
dictionary automaticly add "\" to my jsonstring !
what should i do ?
here is my :
internal var registers : [ [String:String] ] = []
registers.append(["fullName" :"ali","mid" :"406070","phoneNumber":"0912033"])
let jsonData = try! JSONEncoder().encode(registers)
let jsonString = String(data: jsonData, encoding: .utf8)!
let regjson = jsonString
let parameters: [String: String] = [
"registers": regjson
]
and the result is
["registers": "[{\"mid\":\"406070\",\"fullName\":\"ali\",\"phoneNumber\":\"0912033\"}]"]
it should be like this
["registers": [{"fullName":"ali","mid":"406070","phoneNumber":"0912033"}]]
You're taking a dictionary, encoding it into a string of JSON. That process works fine. If you look at regjson, you'll see it's just fine. See for yourself:
let registers = [
["fullName" :"ali","mid" :"406070","phoneNumber":"0912033"]
]
let registersJsonData = try! JSONEncoder().encode(registers)
let registersJsonString = String(data: registersJsonData, encoding: .utf8)!
print(registersJsonString) // Looks just fine.
// => [{"mid":"406070","fullName":"ali","phoneNumber":"0912033"}]
But you're then taking this json string, and putting it another dictionary, and re-serializing the whole thing into yet another json string. The system doesn't know that the string value for the key "registers" is already a JSON-serialized string. It thinks it's a plain string no different than something like "Mary had a little lamb.". It serialized this string, like any other string. Doing so involves escaping out symbols that have other meanings in JSON's syntax.
The system is behaving correctly, you're just asking it to do something that you don't want.
What you're probably looking for is:
let registers = [
["fullName": "ali", "mid" :"406070", "phoneNumber": "0912033"]
]
let parameters = [
"registers": registers
]
let parametersJsonData = try! JSONEncoder().encode(parameters)
let parametersJsonString = String(data: parametersJsonData, encoding: .utf8)!
print(parametersJsonString)
// => {"registers":[{"phoneNumber":"0912033","mid":"406070","fullName":"ali"}]}
what should i do ?
Nothing, the backslashes are virtual. They are added to display double quotes in a literal string.
You might be printing an optional string. Thus the terminal is showing the JSON string as a substring, thus printing line breaks.
In playgrounds, the following code produces an error:
import Foundation
struct Model: Codable {
let textBody: String
enum CodingKeys: String, CodingKey {
case textBody = "TextBody"
}
}
let json = """
{
"TextBody": "First Line\n\nLastLine"
}
""".data(using: .utf8)!
let model = try! JSONDecoder().decode(Model.self, from: json)
Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Unescaped control character around character 27." UserInfo={NSDebugDescription=Unescaped control character around character 27.}))): file MyPlayground.playground, line 19
The JSON above is perfectly valid according to JSONLint. So what gives?
Update:
I need a solution that will handle data returned from an API. Here is something I came up with so far, but it's gross...
if let data = data,
let dataStr = String(data: data, encoding: .utf8),
let cleanData = dataStr.replacingOccurrences(of: "\n", with: "", options: .regularExpression).data(using: .utf8)
{
do {
let response = try JSONDecoder().decode(T.Response.self, from: cleanData)
completion(.success(response))
} catch (let error) {
print(error.localizedDescription)
completion(.failure(ApiError.decoding))
}
}
Your json in your playground is represented incorrectly. It is constructed from a string literal with the \n in it. But that is being replaced newline characters in your string before it’s converted to a Data. But a newline is not permitted within JSON string. You need the two separate characters, namely \ followed by n in your string within the JSON. You can do that by escaping the \ with another \, e.g.:
let json = """
{
"TextBody": "First Line\\n\\nLastLine"
}
""".data(using: .utf8)!
Or, alternatively, in Swift 5 and later, you can use extended string delimiters, such as:
let json = #"""
{
"TextBody": "First Line\n\nLastLine"
}
"""#.data(using: .utf8)!
Or:
let json = #"{"TextBody": "First Line\n\nLastLine"}"#
.data(using: .utf8)!
I’d be very surprised if your web service was returning a JSON with newline characters (0x0a) within its string values, rather than \ character followed by n character. That would only happen if some inexperienced back-end developer was manually building JSON rather than using functions that do this properly.
You say that you’re seeing \n in Postman. That suggests that your server response is correct, that there are two characters, \ followed by n, within the string. For example, here is a web service that echoed my input back and this JSON is well formed with \ followed by n:
If your output looks like the above, then your JSON is valid and the problem in your code snippet above is merely a manifestation of how you represented this JSON in a string literal in Swift code in your playground.
You only need to worry if you see "First line on one line in this Postman “raw” view and see Lastline" on the next line (presumably with no \n).
Bottom line, we should ignore the error in your playground. Parse your actual server response (not cutting-and-copying the JSON into code, or at least not without those extended string literals). Focus on what errors, if any, you get when you parse the actual server response. I wager that if you run your parser on your actual server response, you won’t get this “Unescaped control character” error.
I'm working on JSON serialization like below code:
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: abc, options: .prettyPrinted)
let parsedDict = String(data: jsonData!, encoding: String.Encoding.utf8)
print(" parse Dict Value \(parsedDict!)")
abc data is:
{
"ActedTime" = "2017-09-19 12:04:12",
"EventDate" = "2017-10-06 07:03:29"
}
After completion of serialization, the response value is:
"{\n \"ActedTime\" : \"2017-09-19 12:04:12\",\n \"EventDate\" : \"2017-10-06 07:03:29\”}”
I printed the parsedDict like below:
{
"ActedTime" : "2017-09-19 12:04:12",
"EventDate" : "2017-10-06 07:03:29"
}
The stored data seems like string format, but data is printed like dictionary.
How can I get dictionary format for sent the parameters to another API like dictionary format.
Please help me,
Thanks in Advance.
Omit .prettyPrinted, the server doesn't care anyway.
let jsonData = try? JSONSerialization.data(withJSONObject: abc)
And if the object is supposed to be a dictionary, why do you serialize it at all?
However if the data is supposed to be passed in a POST request as httpBody pass jsonData rather than parsedDict.
In a JSON data file, I have a unicode character like this:
{
”myUnicodeCharacter”: ”\\u{25a1}”
}
I know how to read data from JSON files. The problem occurs when it contains characters which are represented as above.
I read it in to a String variable, myUnicodeCharacterString, which gets the value ”\u{25a1}”. I couldn't by the way use a single slash in the JSON data file because in such case it doesn't recognize the data in the file to be a proper JSON object, returning nil.
However, the value is not encoded to its graphical representation when it’s assigned to something for displaying it, for example a SKLabelNode:
mySKLabelNode.Text = myUnicodeCharacterString // displays ”\u{25a1}” and not a hollow square
The problem boils down to this:
// A: direct approach, does works
let unicodeValueByValue = UnicodeScalar("\u{25a1}") // ”9633”
let c1 = Character(unicodeValueByValue) // ”a hollow square”
// B: indirect approach, this does not work
let myUnicodeString = "\u{25a1}"
let unicodeValueByVariable = UnicodeScalar(myUnicodeString) // Error: cannot find an initialiser
let c2 = Character(unicodeValueByVariable)
So, how do I display a unicode character of the format "\u{xxxx}" if it's not directly given in code?
A better way would be to use the proper \uNNNN escape sequence
for Unicode characters in JSON (see http://json.org for details).
This is automatically handled by NSJSONSerialization, and you don't
have to convert a hex code.
In your case the JSON data should be
{
"myUnicodeCharacter" : "\u25a1"
}
Here is a full self-contained example:
let jsonString = "{ \"myUnicodeCharacter\" : \"\\u25a1\"}"
println(jsonString)
// { "myUnicodeCharacter" : "\u25a1"}
let dict = NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding)!,
options: nil, error: nil) as [String : String]
let myUnicodeCharacterString = dict["myUnicodeCharacter"]!
println(myUnicodeCharacterString)
// □
I came up with a solution, which does not answer the question, but is actually a better way of doing what I'm trying to do.
The unicode character is given instead as its hexadecimal value in the JSON data file, stripping all escape characters:
{
”myUnicodeCharacter”: ”25a1”
}
Then it's processed like this, after reading the value in to myUnicodeCharacterString:
let num = Int(strtoul(myUnicodeCharacterString, nil, 16))
mySKLabelNode.Text = String(UnicodeScalar(num))
And that worked. Now the hollow square showed up.
In Swift, we can implement the following solution
let jsonString = "{ "unicodeCharacter" : "\u00BD"}"
let data = jsonString.data(using: .utf8)
if let data = data {
let dict = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: String]
print(dict?["unicodeCharacter"] ?? "")
}
Output: "½\n"