I am making a call to get a JSON response like this:
NSData *urlData=[NSURLConnection sendSynchronousRequest:serviceRequest returningResponse:&httpResponse error:nil ];
NSString *returnString=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
However, when I print the string using NSLog:
Emiratos �rabes Unidos
When I convert it to NSData like this:
NSData *jsonData = [returnString dataUsingEncoding:NSUTF8StringEncoding];
NSArray * response = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
It turns it to be (when I retrieve the value from the array):
Emiratos \Ufffdrabes Unidos
And when I put it in a label it displays it like this:
Emiratos �rabes Unidos
I would like to display in a label like this:
Emiratos Árabes Unidos
How can I do it?
The problem seems to be this line:
NSString *returnString =
[[NSString alloc] initWithData:urlData
encoding:NSUTF8StringEncoding];
You are assuming that the data is a string encoded as UTF8. But apparently it isn't. Therefore you're seeing the "replacement character" (codepoint U+FFFD) at this point.
You'll need to find out what encoding is actually being used. You can probably just experiment with other encodings. Alternatively, use NSLog to look at the data; an NSData object is logged as a sequence of hex bytes, so by looking at the bytes in that position, and by looking up various encodings on the Internet, you may be able to deduce what encoding is being used here.
(But if you use NSLog and you actually see FFFD at this point, then you've had it; the server itself is supplying the bad data and there's nothing you can do about it, as the good data is lost before you can get at it.)
I have a file with many lines separated by "\n". One of the lines is:
Christian Grundekjøn
I can't read the file unless I delete the line. I use the following code to read line by line:
for (NSString *line in [[NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL] componentsSeparatedByString:#"\n"])
If I don't delete the line, the code wouldn't even go into the for loop at all. Nothing was read. How to handle the non-English letters?
If you are generating the text file from within iOS then you need to make sure you are encoding it with NSUTF8StringEncoding. But given the problem you are reporting, I suspect that you may be pulling in data from another source and that source hasn't encoded the text as UTF8. If this is the case, you may be able to fix the problem outside your app but converting the source file to UTF8.
If you don't know what encoding is used, e.g. because the user has supplied the file, iOS can try to guess it for you. A pattern that I have used successfully is to first try to get the string using UTF8 encoding, for example using the same approach you use. Assuming you write a method, to which you pass a filename, to get the string something like the following:
- (NSString*) stringFromFile: (NSString*) filePath;
{
NSError* error = nil;
NSString* stringFromFile = [NSString stringWithContentsOfFile: fileName
encoding: NSUTF8StringEncoding
error: &error];
if (stringFromFile) return stringFromFile; // success
NSLog(#"String is not UTF8 encoded. Error: %#", [error localizedDescription]);
NSStringEncoding encoding = 0;
NSError* usedEncodingError = nil;
NSString* stringFromFile = [NSString stringWithContentsOfFile: path
usedEncoding: &encoding
error: &usedEncodingError];
if (stringFromFile)
{
NSLog(#"Retrieved string using an alternative encoding. Encoding was: %d", encoding);
return stringFromFile;
}
// either handle error or attempt further explicit unencodings here
return nil;
}
In many cases, usedEncoding works very well. But there are edge cases where trying to figure out an encoding can be very tricky. It all depends on the source file.
I had problem with Japanese characters. My solution was when saving file to doc directory
NSString *fileData = [NSString stringWithFormat:#"%#", noteContent];
BOOL isWriteToFile = [fileData writeToFile:notePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
When reading file content
[[NSString alloc] initWithContentsOfFile:fullNotePath usedEncoding:nil error:nil];
In the file, store your data in unicode format or you can also store special character in unicode format.
I'm using a JSON file which contains non-English characters.Hence when I'm fetching values from this file, it is showing some Chinese like characters in the simulator.In the console, I'm getting values like
\U2021\U00c6\U00e1\U2021\U00c6\U00a9\U2021\U00d8\U00e7\U2021\U00c6\U00b1\U2021\U00d8
\U00e0\U2021\U00c6\U00d8\U2021\U00c6\U00d6\U2021\U00c6\U2264\U2021\U00c6\U2122\U2021
\U00d8\U00e7\U2021\U00c6\U2122\U2021\U00c6\U00b1\U2021\U00d8\U00e0\U2021\U00c6\U00ef
\U2021\U00d8\U00e7 \U2021\U00c6\U00ef\U2021\U00d8\U00c7\U2021\U00c6\U00fc...
Any idea?
Try to print in such way:
NSString *currentString = [[[NSString alloc] initWithData:characterBuffer encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"Converted string: %#", currentString);
where characterBuffer is buffer where you've collected received data, replace NSUTF8StringEncoding with appropriate encoding, used at your server.
I have many files html type. Now i want to get content of them. But the text is not UTF8 format so stringWithContentOfFile function return nil. The problem is i can't convert text of file to UTF8 because there are many files. I tried use WebView but not success. There are any way to read files?
Get the data using dataWithContentsOfFile: method and then convert it into an NSString object using initWithData:encoding: method. You can provide the encoding there.
NSData * data = [NSData dataWithContentsOfFile:filePath];
NSString * fileInString = [[NSString alloc] initWithData:data encoding:yourEncoding];
I'm trying to send the contents of UITextView or UITextField as parameters to a php file
NSString *urlstr = [[NSString alloc] initWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#",nameField.text, tagsField.text, dreamEntry.text];
When i log urlstr, the url format is ok just as long as the UITextView or UITextField don't contain spaces. How would i go about converting the spaces to %20 ?
edit
here is the code at present, which not only crashes but isn't encoding the url properly.
name=John Doe&tags=recurring nightmare&entry=Testing testing testing
is converted to
name=John -1844684964oe&tags=recurringightmare&entry=Testing 4.214929e-307sting -1.992836e+00sting
- (IBAction)sendButtonPressed:(id)sender
{
NSString *urlString = [[NSString alloc] initWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#", nameField.text, tagsField.text, dreamEntry.text];
NSString *encodedString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [[NSURL alloc] initWithString:encodedString];
NSLog(encodedString);
NSLog(urlString);
[urlString release];
[url release];
[encodedString release];
}
Actually, all of the previous answers contain at least some inaccuracies, which for many common values of user provided text in the TextFields would not correctly communicate with the server
stringByAddingPercentEscapesUsingEncoding: percent escapes all characters which are not valid URL characters. This method should applied once to the entire URL.
A previous answer claims that stringByAddingPercentEscapesUsingEncoding: works like the URL building classes in many scripting languages, where you should not apply it to the entire URL string, but it doesn't. Anyone can easily verify this by checking its output for unescaped &s and ?s. So it is fine to apply to the entire string, but it is not enough to apply to your 'dynamic' url content.
The previous answer is right in that you have to do some more work to the names and values that go into your CGI query string. Since CGI is specified by RFC3875, this is often referred to as RFC3875 percent escaping. It makes sure that your names and values don't contain characters that are valid URL characters but which are significant in other parts of the URL (;, ?, :, #, &, =, $, +, {, }, <, >, and ,)
However, it is very important to also finish by doing plain URL percent escapes on the full string to make sure that all characters in the string are valid URL characters. While you don't in your example, in general there could be characters in a 'static' part of the string which are not valid URL characters, so you do need to escape those as well.
Unfortunately, NSString doesn't give us the power to escape the RFC3875 significant characters so we have to dip down into CFString to do so. Obviously using CFString is a pain so I generally add a Category onto NSString like so:
#interface NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding;
#end
#implementation NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding {
CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding);
NSString *rfcEscaped = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#";/?:#&=$+{}<>,",
cfEncoding);
return [rfcEscaped autorelease];
}
#end
With this Category in place, the original problem could be correctly solved with the following:
NSString *urlEscapedBase = [#"http://server.com/file.php" stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedName = [nameField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedTags = [tagsField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedEntry = [dreamEntry.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *urlStr = [NSString stringWithFormat:#"%#?name=%#&tags=%#&entry=%#",
urlEscapedBase,
rfcEscapedName,
rfcEscapedTags,
rfcEscapedEntry];
NSURL *url = [NSURL URLWithString:urlStr];
This is a little variable heavy just be more clear. Also note that the variable list provided to stringWithFormat: should not be nil terminated. The format string describes the precise number of variables that should follow it. Also, technically the strings for query string names (name, tags, entry,..) should be run through stringByAddingPercentEscapesUsingEncoding: as a matter of course but in this small example we can easily see that they contain no invalid URL characters.
To see why the previous solutions are incorrect, imagine that the user input text in dreamEntry.text contains an &, which is not unlikely. With the previous solutions, all text following that character would be lost by the time the server got that text, since the unescaped ampersand would be interpreted by the server as ending the value portion of that query string pair.
You're not supposed to URL-escape the entire string, you're supposed to URL-escape the dynamic components. Try
NSString *urlStr = [NSString stringWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#",
[nameField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[tagsField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[dreamEntry.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
nil];
NSURL *url = [NSURL URLWithString:urlStr];
The second issue with your code (and undoubtedly the reason for the odd printing) is you're passing the string directly to NSLog, so it's being treated as a format string. You need to use
NSLog(#"%#", encodedString);
instead. That will make it print as expected.
Edit: A third issue with your code is you're mixing autoreleased and owned objects, then releasing them all at the end. Go look at the 3 objects you create, and which you subsequently release later. One of them shouldn't be released later because it was produced by a method that did not start with the words alloc, copy, or new. Identifying the object in question is an exercise left to the reader.
You can take your URL and use:
NSString *urlStr = [[NSString alloc] initWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#",nameField.text, tagsField.text, dreamEntry.text];
NSString *encStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];