How to convert properly from NSData to NSString? - iphone

I'm getting weird NSString value after performing a conversion. For example, I have one byte with value 2 (00000010) that is stored in response. I tried both NSString initWithData and initWithBytes but both return weird symbol (upside down question mark). Here's my code:
NSString *command1 = [[NSString alloc] initWithData:response encoding:NSASCIIStringEncoding];
NSString *command2 = [[NSString alloc] initWithBytes:[response bytes] length:[response length] encoding:NSASCIIStringEncoding];
NSLog(#"command1: %#", command1);
NSLog(#"command2: %#", command2);
Also tried NSUTF8StringEncoding but NSASCIIStringEncoding is correct one because data comes encoded one byte per symbol.

From what I am reading, this is what you want:
NSString *stringWithContentsOfBinaryData(NSData *data)
{
NSMutableString *output;
int len = [data length];
uint8_t *bytes = [data bytes];
for (int i = 0; i < len; i++)
{
[output appendFormat:#"%i", bytes[i]];
}
return output;
}
It just simply converts each byte to it's integer representation and concatenates that into a string.

ASCII is not necessarily the right encoding. ASCII only defines characters between 0x00 and 0x7F. If response is an HTTP response, and the encoding is not specified in the HTTP Content-Type header, the default is ISO-8859-1 for which you should use NSISOLatin1StringEncoding
And it doesn't matter what encoding you use: control characters (0x00 - 0x1F) aren't necessarily printable.

Related

NSString unichar from int

I have an int value which I obtained from the character 爸, which is 29240. I can convert this number to hex, but I have no clue how to write the chinese character out in an NSString with only the int 29240.
Basically, what I did was:
NSString * s = #"爸";
int a = [s characterAtIndex:0];
NSLog(#"%d", a);
What it gave as output was 29240.
However, I don't know how to create an NSString that just contains 爸 from only the int 29240.
I converted 29240 into binary which gave me 7238, but I can't seem to create a method which allows me to input any integer and NSLog the corresponding character.
I can hard code it in, so that I have
char cString[] = "\u7238";
NSData *data = [NSData dataWithBytes:cString length:strlen(cString)];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"result string: %#", string);
But I'm not sure how to do it with any int.
Thanks to anyone who can help me!
To create a string from one (or more) Unicode characters use initWithCharacters:
unichar c = 29240;
NSString *string = [[NSString alloc] initWithCharacters:&c length:1];
NSString uses UTF-16 characters internally, so
this works for all characters in the "Basic Multilingual Plane", i.e. all characters up to U+FFFF. The following code works for arbitrary characters:
uint32_t ch = 0x1F60E;
ch = OSSwapHostToLittleInt32(ch); // To make it byte-order safe
NSString *s1 = [[NSString alloc] initWithBytes:&ch length:4 encoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"%#", s1);
// Output: 😎
Try out this code snippet to get you started in the right direction:
NSString *s = #"0123456789";
for (int i = 0; i < [s length]; i++) {
NSLog(#"Value: %d", [s characterAtIndex:i]);
}
Just pass in the character as an integer:
unichar decimal = 12298;
NSString *charStr = [NSString stringWithFormat:#"%C", decimal];

Convert a hash to NSString?

Using the Evernote API, I have an object which has an NSUInteger property called hash. For the specific object I'm looking at, this is equal to:
<f5b5444b 33e740b7 f9d49a3b ddb6a39c>
I want to convert this into an NSString. Doing this:
[NSString stringWithFormat:#"%d", noteResource.hash]
Gives me this:
530049088
How could I correctly convert the hash value to an NSString?
When you see something output as "<" 8 hex digits space .... ">", it's the result of logging a NSData object (NSLog(#"%#", myDataObject);). So I believe what you have is not an NSUInteger, but a NSData * object.
There is no built in method to convert between strings and data, you need to do it in code:
- (NSString *)dataToString:(NSData *)data
{
NSUInteger len = [data length];
NSMutableString *str = [NSMutableString stringWithCapacity:len*2];
const uint8_t *bptr = [data bytes];
while(len--) [str appendFormat:#"%02.2x", *bptr++];
return str;
}
If this works, you can write your own stringToData method reversing the above, if needed.

Converting NSString, data type expression, to actual NSData

NSString *string1 = #"<616263>";
I want to make this into NSData *data1 = <616263>;
so that when I
NSString *string2 = [[NSString alloc] initWithData:data1 encoding:NSUTF8StringEncoding];
NSLog(#"%#", string2);
Result: abc
would come out
p.s.
<616263>, this is data expression of #"abc"
The trick is converting 616263 to abc. Since you are starting with the ASCII representation of the character codes, you need to convert your NSString to an array of bytes (or your original data source to an array instead of saving it as an NSString in the first place).
NSString *string1 = #"616263";
// Make sure that buffer is big enough!
char sourceChars[7];
[string1 getCString:sourceChars maxLength:7 encoding:NSUTF8StringEncoding];
char destBuffer[3];
char charBuffer[3];
// Loop through sourceChars and convert the ASCII character groups to char's
// NOTE: I assume that these are always two character groupings per your example!
for (int index = 0; index < [string1 length]; index = index + 2) {
// Copy the next two digits into charBuffer
strncpy(charBuffer, &sourceChars[index], 2);
charBuffer[2] = '\0';
// convert charBuffer (ie 61) from hex to decimal
destBuffer[index / 2] = strtol(charBuffer, NULL, 16);
}
// destBuffer is properly formatted: init data1 with it.
NSData *data1 = [NSData dataWithBytes:destBuffer length:[string1 length]/2];
// Test
NSString *string2 = [[NSString alloc] initWithData:data1 encoding:NSUTF8StringEncoding];
NSLog(#"%#", string2); // Prints abc

Encoding hex value with UTF8 of Ascii representation

I have a nsdata with bytes :0017c572 528e
now i need to encode this byte using either UTF 8 of Ascii
For this i have used following code in Objective C
NSString *Str = [[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding];
then later on at some point i need to get back the same bytes from Str for this i have used
NSData *aData = [Str dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"aData:%#", aData);
Now the problem is content of aData is null not 0017c572 528e . how can i do the this operation.
this concept works perfectly if data byte is : 323332
str = 232
aData = 323332
Just print the Str value before the line
NSLog(#"Str = %#",Str);
NSData *aData = [Str dataUsingEncoding:NSUTF8StringEncoding];
It seems the Str variable does not have any value. Then only, it will return null. Please check.

NSData to NString conversion problem

I'm getting an HTML file as NSData and need to extract some parts of it. For that I need to convert it to NSString with UTF8 encoding. The thing is that this conversion fails, probably because the NSData contains bytes that are invalid for UTF8. I have tried to get the byte array of the data and go over it, but each time I come across non ASCII character (hebrew letters for example) I get jibrish.
Help will be appreciated.
UPDATE:
To Gordon - the NSData generated like that:
NSData *theData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
When I say that the conversion fails I mean that
[[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding]
returns nil
To Ed - Here is my code (I got the Byte array from NSData, found what I need, and constructed another Byte array from that - turned it to NSData and then attempted to convert it to NSString... sounds kinda complicated...)
-(NSString *)UTF8StringFromData:(NSData *)theData{
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = (Byte *)malloc(sizeof(Byte)*((end1-begin1+1)));
NSLog(#"%d %d",begin1, end1);
int j = 0;
for (int i = begin1; i < end1; i++){
arr1[j] = arr[i];
j++;
}
arr1[j]='\0';
NSData *temp = [NSData dataWithBytes:arr1 length:j];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
I know this is an old topic but it came up when I was looking for the solution today. I've solved it now so I'm just posting it for others who might run into this page looking for a solution.
Here's what I do in an asynchronous request:
I first store the text encoding name in connection:didReceiveResponse using
encodingName = [[NSString alloc] initWithString:[response textEncodingName]];
Then later in my connectionDidFinishLoading method I used
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encodingName));
NSString *payloadAsString = [[NSString alloc] initWithData:receivedData encoding:encoding];
To Gordon - the NSData generated like that:
NSData *theData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&theResponse error:&theError];
When I say that the conversion fails I mean that
[[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding]
returns nil
To Ed - Here is my code (I got the Byte array from NSData, found what I need, and constructed another Byte array from that - turned it to NSData and then attempted to convert it to NSString... sounds kinda complicated...)
-(NSString *)UTF8StringFromData:(NSData *)theData{
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = (Byte *)malloc(sizeof(Byte)*((end1-begin1+1)));
NSLog(#"%d %d",begin1, end1);
int j = 0;
for (int i = begin1; i < end1; i++){
arr1[j] = arr[i];
j++;
}
arr1[j]='\0';
NSData *temp = [NSData dataWithBytes:arr1 length:j];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
have you checked the charset= in the HTTP headers and/or the document itself? The most likely reason for the conversion to fail is because the bytes don't represent a valid UTF-8 string.
I'm not sure if you're aware, you don't really need to copy the array to another array before putting it into the new NSData object.
-(NSString *)UTF8StringFromData:(NSData *)theData {
Byte *arr = [theData bytes];
NSUInteger begin1 = [self findIndexOf:#"<li>" bArr:arr size:[theData length]]+4;
NSUInteger end1 = [self findIndexOf:#"</li></ol>" bArr:arr size:[theData length]];
Byte *arr1 = arr + begin1;
NSData *temp = [NSData dataWithBytes:arr1 length:end1 - begin1];
return [[NSString alloc] initWithData:temp encoding:NSUTF8StringEncoding];
}
As for your particular problem, I would try looking through the data manually using the debugger. Put a breakpoint after you have your array (arr1). When you hit it, open up the GDB console and try this:
print (char *)arr1
With your code, it should print out the string you're trying to get. (With the code I gave above, it won't stop after the . It'll just keep going).
If the result is not what you expect, then there's something wrong with the data, or perhaps with your begin1 and end1 boundaries.