stringWithFormat produces string with gibberish characters - ios

When debugging the following code
NSString *var1 = #"blaa";
NSString *var2 = #"blaaaaa";
NSString* script = [NSString stringWithFormat:#"Set_Variable( %s, %s )",var1,var2];
the %s placeholders in script are replaced with funny gibberish characters.
Can you see any errors in the code?

%s is the format specifier for a C string, char*
For objective-c objects (such as NSString) you should use %#

Related

Objective C: Replace double backslash with a single backslash

I'm trying to replace a string that holds double backslash to a string with only single backslash, for example:
\\This\\Is\\Not\\Working
To:
\This\Is\Not\Working
Using:
str = [str stringByReplacingOccurrencesOfString:#"\\\\" withString#"\\"];
But for some reason, The string remains the same (with the double backslash) every single time. What am i doing wrong here?
Sadly, I misinterpreted the console log output. the string was fine, the debugger just showed the single slash as a doubled one. (For escaping purposes i'd imagine).
The below lines of code is fine:
NSString *str=#"\\This\\Is\\Not\\Working";
str = [str stringByReplacingOccurrencesOfString:#"\\\\" withString#"\\"];
Just check value by NSLog or by printing, because in debug console slash is represented as double slash.
Check image for more clear understanding:
NSString *Str = #"\\This\\Is\\Not\\Working";
NSLog(#"%#",Str);// print:-\This\Is\Not\Working
Str = [Str stringByReplacingOccurrencesOfString:#"\\\\" withString:#"\\"];// in this no replace occurres
NSLog(#"%#",Str); // print:-\This\Is\Not\Working
NSString *Str1 = #"\\\\This\\\\Is\\\\Not\\\\Working";
NSLog(#"%#",Str1);// print:-\\This\\Is\\Not\\Working
Str1 = [Str1 stringByReplacingOccurrencesOfString:#"\\\\" withString:#"\\"];
NSLog(#"%#",Str1);// print:-\This\Is\Not\Working
Try this:
NSString *str = #"\\This\\Is\\Not\\Working";
str = [str stringByReplacingOccurrencesOfString:#"\\" withString:#"\\\\"];
NSLog(#"%#", [str stringByReplacingOccurrencesOfString:#"\\\\" withString:#"\\"]);
1st Line is your user input.
2nd Line converts the double back-slashed user input string into four back-slashed string
3rd line simply replaces four back slashes with two back slashes which results in printing single back slash

How to put unicode char into NSString

For example I could type an emoji character code such as:
NSString* str = #"😊";
NSLog(#"%#", str);
The smile emoji would be seen in the console.
Maybe the code editor and the compiler would trade the literal in UTF-8.
And now I'm working in a full unicode, I mean 32bit per char, environment and I've got the unicode of the emoji, I want to convert the 32bit unicode into a NSString for example:
int charcode = 0x0001F60A;
NSLog(#"%??", charcode);
The question is what should I put at the "??" position and then I could format the charcode into a emoji string?
BTW the charcode was a variable which can not be determine at the compile time.
I don't want to compress the 32bit int into UTF-8 bytes unless that would be the only way.
If 0x0001F60A is a dynamic value determined at runtime then
you can use the NSString method
- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding;
to create a string containing a character with the given Unicode value:
int charcode = 0x0001F60A;
uint32_t data = OSSwapHostToLittleInt32(charcode); // Convert to little-endian
NSString *str = [[NSString alloc] initWithBytes:&data length:4 encoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"%#", str); // 😊
Use NSString initialization method
int charcode = 0x0001F60A;
NSLog(#"%#", [[NSString alloc] initWithBytes:&charcode length:4 encoding:NSUTF32LittleEndianStringEncoding]);

NSLog() vs printf() when printing C string (UTF-8)

I have noticed that if I try to print the byte array containing the representation of a string in UTF-8, using the format specifier "%s", printf() gets it right but NSLog() gets it garbled (i.e., each byte printed as-is, so for example "¥" gets printed as the 2 characters: "¬•").
This is curious, because I always thought that NSLog() is just printf(), plus:
The first parameter (the 'format') is an Objective-C string, not a C
string (hence the "#").
The timestamp and app name prepended.
The newline automatically added at the end.
The ability to print Objective-C objects (using the format "%#").
My code:
NSString* string;
// (...fill string with unicode string...)
const char* stringBytes = [string cStringUsingEncoding:NSUTF8Encoding];
NSUInteger stringByteLength = [string lengthOfBytesUsingEncoding:NSUTF8Encoding];
stringByteLength += 1; // add room for '\0' terminator
char* buffer = calloc(sizeof(char), stringByteLength);
memcpy(buffer, stringBytes, stringByteLength);
NSLog(#"Buffer after copy: %s", buffer);
// (renders ascii, no matter what)
printf("Buffer after copy: %s\n", buffer);
// (renders correctly, e.g. japanese text)
Somehow, it looks as if printf() is "smarter" than NSLog(). Does anyone know the underlying cause, and if this feature is documented anywhere? (Couldn't find)
NSLog() and stringWithFormat: seem to expect the string for %s
in the "system encoding" (for example "Mac Roman" on my computer):
NSString *string = #"¥";
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding());
const char* stringBytes = [string cStringUsingEncoding:enc];
NSString *log = [NSString stringWithFormat:#"%s", stringBytes];
NSLog(#"%#", log);
// Output: ¥
Of course this will fail if some characters are not representable in the system encoding. I could not find an official documentation for this behavior, but one can see that using %s in stringWithFormat: or NSLog() does not reliably work with arbitrary UTF-8 strings.
If you want to check the contents of a char buffer containing an UTF-8 string, then
this would work with arbitrary characters (using the boxed expression syntax to create an NSString from a UTF-8 string):
NSLog(#"%#", #(utf8Buffer));

Xcode - UTF-8 String Encoding

I have a strange problem encoding my String
For example:
NSString *str = #"\u0e09\u0e31\u0e19\u0e23\u0e31\u0e01\u0e04\u0e38\u0e13";
NSString *utf = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog("utf: %#", utf);
This worked perfectly in log
utf: ฉันรักคุณ
But, when I try using my string that I parsed from JSON with the same string:
//str is string parse from JSON
NSString *str = [spaces stringByReplacingOccurrencesOfString:#"U" withString:#"u"];
NSLog("str: %#, str);
NSString *utf = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog("utf: %#", utf);
This didn't work in log
str: \u0e09\u0e31\u0e19\u0e23\u0e31\u0e01\u0e04\u0e38\u0e13
utf: \u0e09\u0e31\u0e19\u0e23\u0e31\u0e01\u0e04\u0e38\u0e13
I have been finding the answer for hours but still have no clue
Any would be very much appreciated! Thanks!
The string returned by JSON is actually different - it contains escaped backslashes (for each "\" you see when printing out the JSON string, what it actually contains is #"\").
In contrast, your manually created string already consists of "ฉันรักคุณ" from the beginning. You do not insert backslash characters - instead, #"\u0e09" (et. al.) is a single code point.
You could replace this line
NSString *utf = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
with this line
NSString *utf = str;
and your example output would not change. The stringByReplacingPercentEscapesUsingEncoding: refers to a different kind of escaping. See here about percent encoding.
What you need to actually do, is parse the string for string representations of unicode code points. Here is a link to one potential solution: Using Objective C/Cocoa to unescape unicode characters. However, I would advise you to check out the JSON library you are using (if you are using one) - it's likely that they provide some way to handle this for you transparently. E.g. JSONkit does.

3rd Party Language support (Xcode + iOS) [duplicate]

I've got a problem with the following code:
NSString *strValue=#"你好";
char temp[200];
strcpy(temp, [strValue UTF8String]);
printf("%s", temp);
NSLog(#"%s", temp);
in the first line of the codes, two Chinese characters are double quoted. The problem is printf function can display the Chinese characters properly, but NSLog can't.
Thanks to all. I figured out a solution for this problem. Foundation uses UTF-16 by default, so in order to use NSLog to output the c string in the example, I have to use cStringUsingEncoding to get UTF-16 c string and use %S to replace %s.
NSString *strValue=#"你好";
char temp[200];
strcpy(temp, [strValue UTF8String]);
printf("%s", temp);
strcpy(temp, [strValue cStringUsingEncoding:NSUTF16LittleEndianStringEncoding]);
NSLog(#"%S", temp);
NSLog's %s format specifier is in the system encoding, which seems to always be MacRoman and not unicode, so it can only display characters in MacRoman encoding. Your best option with NSLog is just to use the native object format specifier %# and pass the NSString directly instead of converting it to a C String. If you only have a C string and you want to use NSLog to display a message instead of printf or asl, you will have to do something like Don suggests in order to convert the string to an NSString object first.
So, all of these should display the expected string:
NSString *str = #"你好";
const char *cstr = [str UTF8String];
NSLog(#"%#", str);
printf("%s\n", cstr);
NSLog(#"%#", [NSString stringWithUTF8String:cstr]);
If you do decide to use asl, note that while it accepts strings in UTF8 format and passes the correct encoding to the syslog daemon (so it will show up properly in the console), it encodes the string for visual encoding when displaying to the terminal or logging to a file handle, so non-ASCII values will be displayed as escaped character sequences.
My guess is that NSLog assumes a different encoding for 8-bit C-strings than UTF-8, and it may be one that doesn't support Chinese characters. Awkward as it is, you might try this:
NSLog(#"%#", [NSString stringWithCString: temp encoding: NSUTF8StringEncoding]);
I know you are probably looking for an answer that will help you understand what's going on.
But this is what you could do to solve your problem right now:
NSLog(#"%#", strValue);
# define NSLogUTF8(a,b) NSLog(a,[NSString stringWithCString:[[NSString stringWithFormat:#"%#",b] cStringUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding])
#define NSLogUTF8Ex(a,b) NSLog(a,[MLTool utf8toNString:[NSString stringWithFormat:#"%#",b]])
+(NSString*)utf8toNString:(NSString*)str{
NSString* strT= [str stringByReplacingOccurrencesOfString:#"\\U" withString:#"\\u"];
//NSString *strT = [strTemp mutableCopy];
CFStringRef transform = CFSTR("Any-Hex/Java");
CFStringTransform((__bridge CFMutableStringRef)strT, NULL, transform, YES);
return strT;
}

Resources