Web Service JSON nsdictionary unicode string [duplicate] - objective-c

NSData* jsonData is the http response contains JSON data.
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"jsonString: %#", jsonString);
I got the result:
{ "result": "\u8aaa" }
What is the proper way to encoding the data to the correct string, not unicode string like "\uxxxx"?

If you convert the JSON data
{ "result" : "\u8aaa" }
to a NSDictionary (e.g. using NSJSONSerialization) and print the dictionary
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSLog(#"%#", jsonDict);
then you will get the output
{
result = "\U8aaa";
}
The reason is that the description method of NSDictionary uses "\Unnnn" escape sequences
for all non-ASCII characters. But that is only for display in the console, the dictionary is correct!
If you print the value of the key
NSLog(#"%#", [jsonDict objectForKey:#"result"]);
then you will get the expected output
說

I don't quite understand what the problem is. AFNetworking has given you a valid JSON packet. If you want the above code to output the character instead of the \u… escape sequence, you should coax the server feeding you the result to change its output. But this shouldn't be necessary. What you most likely want to do next is run it through a JSON deserializer…
NSDictionary * data = [NSJSONSerialization JSONObjectWithData:jsonData …];
…and you should get the following dictionary back: #{#"result":#"說"}. Note that the result key holds a string with a single character, which I'm guessing is what you want.
BTW: In future, I suggest you copy-paste output into your question rather than transcribing it by hand. It'll avoid several needless rounds of corrections and confusion.

Related

JSON data has "bad" characters that causes NSJSONSerialization to die

I am using the ATV version of TVH Client - if you haven't looked at this it's worth looking at TVH to glimpse madness in the face. It has a JSON API that sends back data, including the electronic program guide. Sometimes the channels put accented characters in their data. Here is an example, this is the result from Postman, note the ? char in the description:
{
"eventId": 14277,
"episodeId": 14278,
"channelName": "49.3 CometTV",
"channelUuid": "02fe96403d58d53d71fde60649bf2b9a",
"channelNumber": "49.3",
"start": 1480266000,
"stop": 1480273200,
"title": "The Brain That Wouldn't Die",
"description": "Dr. Bill Cortner and his fianc�e, Jan Compton , are driving to his lab when they get into a horrible car accident. Compton is decapitated. But Cortner is not fazed by this seemingly insurmountable hurdle. His expertise is in transplants, and he is excited to perform the first head transplant. Keeping Compton's head alive in his lab, Cortner plans the groundbreaking yet unorthodox surgery. First, however, he needs a body."
},
If this data is fed into NSJSONSerialization, it returns an error. So to avoid this, the data is first fed into this function:
+ (NSDictionary*)convertFromJsonToObjectFixUtf8:(NSData*)responseData error:(__autoreleasing NSError**)error {
NSMutableData *FileData = [NSMutableData dataWithLength:[responseData length]];
for (int i = 0; i < [responseData length]; ++i) {
char *a = &((char*)[responseData bytes])[i];
if ( (int)*a >0 && (int)*a < 0x20 ) {
((char*)[FileData mutableBytes])[i] = 0x20;
} else {
((char*)[FileData mutableBytes])[i] = ((char*)[responseData bytes])[i];
}
}
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:FileData //1
options:kNilOptions
error:error];
if( *error ) {
NSLog(#"[JSON Error (2nd)] output - %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
NSDictionary *userInfo = #{ NSLocalizedDescriptionKey:[NSString stringWithFormat:NSLocalizedString(#"Tvheadend returned malformed JSON - check your Tvheadend's Character Set for each mux and choose the correct one!", nil)] };
*error = [[NSError alloc] initWithDomain:#"Not ready" code:NSURLErrorBadServerResponse userInfo:userInfo];
return nil;
}
return json;
}
This cleans up the case when there is a control character in the data, but not an accent like the case above. When I feed in that data I get the "Tvheadend returned malformed JSON" error.
One problem is that the user can change the character set among a limited number of selections, and the server does not tell the client what it is. So one channel might use UTF8 and another ISO-8891-1, and there is no way to know which to use on the client side.
So: can anyone offer a suggestion on how to process this data so we feed clean strings into NSJSONSerialization?
I still do not know the root cause of the problem I am seeing - the server is sending not only high-bit characters like the ones I noted above, but I also found that it contained control characters too! Looking over other threads it appears I am not the only one seeing this problem, so hopefully others will find this useful...
The basic trick is to convert the original data from the server to a string using UTF8. If there are any of these "bad" chars in it, the conversion will fail. So you check if the resulting string is empty, and try another charset. Eventually you'll get data back. Now you take that string and strip out any control chars. Now you take that result, which is now UTF8 "clean", and convert it back to UTF8 NSData. That will pass through the JSON conversion without error. Phew!
Here is the solution I finally used:
// ... the original data from the URL is in responseData
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ( str == nil ) {
str = [[NSString alloc] initWithData:responseData encoding:NSISOLatin1StringEncoding];
}
if ( str == nil ) {
str = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
}
NSCharacterSet *controls = [NSCharacterSet controlCharacterSet];
NSString *stripped = [[str componentsSeparatedByCharactersInSet:controls] componentsJoinedByString:#""];
NSData *data = [stripped dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
I hope someone finds this useful!

JSON file read 3840 error

Reading this file city.list.us.json.gz (uncompressed) gets an error (3840) doing:
NSString * path = [mb pathForResource:#"city.list.us" ofType:#"json" inDirectory:#"JSON"];
NSString * string = [NSString stringWithContentsOfUTF8File:path];
NSData * data = [string dataUsingEncoding:NSASCIIStringEncoding];
NSLog(#"isValidJSONObject:%#", [NSJSONSerialization isValidJSONObject:data] ? #"Yes" : #"No");
NSError * bobo = nil;
id blob = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&bobo];
[NSApp presentError:bobo];
which reads ok - length 1873878 bytes, looks ok in vi (set list), but does not yield a non-nil object.
A head -4 of the file shows:
{"_id":4070245,"name":"Jones Crossroads","country":"US","coord":{"lon":-85.484657,"lat":31.21073}}
{"_id":4344544,"name":"Vernon Parish","country":"US","coord":{"lon":-93.183502,"lat":31.11685}}
{"_id":4215307,"name":"Pennick","country":"US","coord":{"lon":-81.55899,"lat":31.313}}
{"_id":5285039,"name":"Black Bear Spring","country":"US","coord":{"lon":-110.288139,"lat":31.386209}}
To my un-expert JSON eyes, it appears this is a file of cites, has an object per line with 4 values (_id,name,country,coord), last an object containing 2 values (lat,lon).
Also tried NSASCIIStringEncoding for the NSData conversion but no joy.
Any ideas?
That's not valid JSON. It's a large number of JSON dictionaries but they are not related to each other.
Most likely the expected JSON (an array of dictionaries) is supposed to look like
[{"_id":4070245,"name":"Jones Crossroads","country":"US","coord":{"lon":-85.484657,"lat":31.21073}},
{"_id":4344544,"name":"Vernon Parish","country":"US","coord":{"lon":-93.183502,"lat":31.11685}},
{"_id":4215307,"name":"Pennick","country":"US","coord":{"lon":-81.55899,"lat":31.313}},
{"_id":5285039,"name":"Black Bear Spring","country":"US","coord":{"lon":-110.288139,"lat":31.386209}}]
I wrapped the whole text in square brackets [] and added commas at the end of each line.

Any shortcut or open source code can format a JSON String with proper indentation in Objective-C

Problem:
Every time, when I got a JSON string from Web Server, it looks like this:
{"array":[1,2,3],"boolean":true,"null":null,"number":123,"object":{"a":"b","c":"d","e":"f"},"string":"Hello World"}
I really wanna re-organise string format to NSLog() it like this:
{
"array": [
1,
2,
3
],
"boolean": true,
"null": null,
"number": 123,
"object": {
"a": "b",
"c": "d",
"e": "f"
},
"string": "Hello World"
}
Question:
Is there any shortcut to format JSON NSString with proper indentation and line feeds? (I know [NSDictionary description])
P.S.
Sometimes, the JSON NSString has prefix string like this:
Web Service response is : {"array":[1,2,3],"boolean":true,"null":null,"number":123,"object":{"a":"b","c":"d","e":"f"},"string":"Hello World"}
Any method or regular-expression can grab JSON string out of the paragraph?
Try this
NSData *data = [NSJSONSerialization dataWithJSONObject:temp options:NSJSONWritingPrettyPrinted error:nil ];
NSString* aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"result: %#", aStr);
Here's some code that will strip leading characters up to the first curly brace and display the JSON data nicely formatted on the debug console.
NSRange range = [str rangeOfString:#"{"];
if ( range.location != NSNotFound )
str = [str substringFromIndex:range.location];
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog( #"%#", jsonData );
Try to parse it to an Object first and see what happens if you print it then. With a little luck the textual representation of Array's and Dictionaries will get you on your way. Right now you are printing a string, which will always look a little something like that.
Obviously you could write some code that recognizes the curly brackets and commas and based on that adds in line-endings and indentations. Should not be too hard, but the question is why would you want that?
If you use it to debug, just put a breakpoint there and look at the object in your code in XCode with the inspector. That will show you the object and the objects withing and give you an option to print it's representation to the console.

Emojis displaying as boxes

I am making an app that posts content from a UITextField, to a PHP script, and store in a database to read later. I am having one heck of a time working with emojis.
Using json, I will get a response like this:
content = "\Uf44d";
id = 104;
time = 1350359055;
In this instance, I used an emoji. But when I do [dictionary objectForKey:#"content"], a box just appears. 
I'm thinking I need to convert to UTF-8. But I'm not completely sure. Please help!
U+F44D is a Unicode character in the "Private Use Area" U+E000..U+F8FF, so that is probably not the character you want to display.
On the other hand, U+1F44D is the "THUMBS UP SIGN", so it could be that your Web service does not create a correct JSON response for Unicode characters greater than 0xFFFF.
According to the JSON RFC, characters that are not part of the "Basic Multilingual Plane" can be escaped using a UTF-16 surrogate pair. For the U+1F44D character the JSON Unicode escape sequence would be "\ud83d\udc4d".
The following code shows that it works in general:
const char *s = "{ \"content\": \"\\ud83d\\udc4d\", \"id\": 104, \"time\": 1350359055 }";
NSData *jsonData = [NSData dataWithBytes:s length:strlen(s)];
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
self.label.text = [jsonDict objectForKey:#"content"];
This displays the "THUMBS UP SIGN" correctly in the label.
But you don't have to escape characters, the Web service could also just send the UTF-8 sequence.
I hope this will help you...I'm using this and e106 is my emoji code.
Only replcare with content line with below line:
content = [NSString stringWithFormat:#"%C", 0xe106];

How to parse a JSON having no quotes with its KEY string?

I want to parse the json output resulting from the following url in SBJSON framework for iOS
http://maps.google.com/maps?q=school&mrt=yp&sll=13.006389,80.2575&output=json
while(1);{title:"school - Google Maps",url:"/maps?q=school\x26mrt=yp\x26sll=13.006389,80.2575\x26ie=UTF8\x26hq=school\x26hnear=",urlViewport:false,ei:"RCu3T4eeMqSiiAe7k-yZDQ",form:{selected:"q",q:{q:"school",mrt:"yp",what:"school",near:""},d:{saddr:"",daddr:"",dfaddr:""},geocode:""},
I am using http://www.bodurov.com/JsonFormatter/ to read it online.
In ASIHttpRequest response method I removed while(1); from the response
NSString *responseString = [[request resonseString]substringFromIndex:9]; //to remove while(1)
SBJSONParser * parser = [[SBJSONParser alloc]init];
NSDictionary *jsonDict = (NSDictionary*)[parser objectFromString:responseString];
NSLog(#"%#",jsonDict) // prints null
// [responseString JSONValue] also reports error
I guess JSON key without double quotes is causing problem.
Instead of {
"title": "hospital - Google Maps",
"urlViewport": false,
}, we get {
title: "hospital - Google Maps",
"urlViewport": false
}
Please help me to parse this complex JSON structure returned from Google.
This worked better for my case because my values contained times which caused the regular expression in the above answer to match incorrectly.
json = [json stringByReplacingOccurrencesOfString: #"(\\w*[A-Za-z]\\w*)\\s*:"
withString: #"\"$1\":"
options: NSRegularExpressionSearch
range: NSMakeRange(0, json.length)];
You need to add the missing quotes to the keys, so try this:
responseString = [responseString stringByReplacingOccurrencesOfString:#"(\\w+)\\s*:"
withString:#"\"$1\":"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [responseString length])];
This should work well with the given JSON string.