UITableView Headers with UTF-8 Strings? - ios

I'm formatting my UITableView headers with Unix %s formatting because the Objective C format code %# doesn't handle padding (e.g. %20#%20s). Unfortunately, if I have accented foreign characters, they aren't displayed properly. The word "voilà" appears like this:
Here's how I generate my table header:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
...
//NSString *tblHdr = [NSString stringWithFormat:#"%12s", #"voilà"];
NSString *tblHdr = [NSString stringWithFormat:#"%12s", [#"voilà" UTF8String]]; // Fixed example
...
return tblHdr;
}
[Update]
Here's the actual code from my project. I tried to keep it simple in my original example:
tblHdr = [NSString stringWithFormat:#"%-45s%12s%12s%35s",
[NSLocalizedString(#"Quiz Name", #"") UTF8String],
[NSLocalizedString(#"Correct", #"") UTF8String],
[NSLocalizedString(#"Missed", #"") UTF8String],
[NSLocalizedString(#"Score", #"") UTF8String]
];

It seems that the %s format expects a C string in the system encoding,
so this works
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding());
NSString *s = [NSString stringWithFormat:#"%12s", [#"voilá" cStringUsingEncoding:enc]];
(as long as the string can be represented in the system encoding).
Otherwise you can pad the string manually:
NSString *t = #"voilá";
if ([t length] < 12) {
t = [[#"" stringByPaddingToLength:(12 - [t length]) withString:#" " startingAtIndex:0] stringByAppendingString:t];
}
(or use #Daij-Djan's method, which was posted while I wrote this).

issue: %s formats a char* which is != NSString. so:
NSString *tblHdr = [NSString stringWithFormat:#"%12s", #"voilà".UTF8String];
This doesn't work as %s seems to not do multibyte right IMO!? Not sure
I'd stick with NSStrings... just add the spaces manually
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
//wrong
NSString *tblHdr = [NSString stringWithFormat:#"%12s", #"voilà".UTF8String];
NSLog(#"%#", tblHdr);
//ok
NSMutableString *rawTblHdr = #"voilà".mutableCopy;
while(12-rawTblHdr.length) {
[rawTblHdr insertString:#" " atIndex:0];
}
NSLog(#"%#", rawTblHdr);
}
}

Related

Objective C - How to compare string from the console

My code always returns "fail" for the following string comparison using isEqualToString. What is the correct way to compare strings coming from the console?
char buf[MAX_LENGTH];
fgets(buf, MAX_LENGTH, stdin);
NSString *s = [[NSString alloc] initWithUTF8String:buf];
NSLog(#"You typed %#", s);
NSString *n = #"exit";
if ([n isEqualToString:s]) {
NSLog(#"success!");
} else {
NSLog(#"fail");
}
The result of fgets contains "\n", So you need define your "n" as this:
NSString *n = #"exit\n";
Or remove the "\n" from "s":
NSString *s = [[NSString alloc] initWithUTF8String:buf];
s = [s stringByReplacingOccurrencesOfString:#"\n" withString:#""];

How to convert HEX to NSString in Objective-C j?

I have a NSString with hex string like "&# x62a;&# x631;&# x642;&# x628;" which means "ترقب".
Now I want to convert the hex string into another NSString object which shows "ترقب". How to do that ?
- (NSMutableString *) hextostring:(NSString *) str{
//ت
NSMutableString *string = [[NSMutableString alloc]init];
str = [str stringByReplacingOccurrencesOfString:#"&#" withString:#"0"];
str = [str stringByReplacingOccurrencesOfString:#" " withString:#"z;"];
NSArray *arr = [str componentsSeparatedByString:#";"];
for (int i =0; i<[arr count]; i++) {
if ([[arr objectAtIndex:i] isEqualToString:#"z"]) {
[string appendString:#" "];
} else {
unsigned x;
[[NSScanner scannerWithString: [arr objectAtIndex:i]] scanHexInt: &x];
[string appendFormat:#"%C",(unichar)x];
}
}
NSLog(#"%#",string);
return string;
}
Your string looks like HTML escape sequences, except for the spaces after the #'s. If this is really what you have (check something isn't just displaying Unicode as escapes) then there is a myriad of ways to convert it. You can just process the string picking out the hex chars and producing UniChar values from them, etc.
If you want a high-level, maybe somewhat long-winded approach, you and try:
- (NSString *)decodeHTMLescapes:(NSString *)raw
{
NSString *nospaces = [raw stringByReplacingOccurrencesOfString:#" " withString:#""]; // one way to remove the spaces
const char *cString = [nospaces UTF8String]; // C string
NSData *bytes = [[NSData alloc] initWithBytesNoCopy:(void *)cString length:strlen(cString) freeWhenDone:NO]; // as bytes
NSAttributedString *attributed = [[NSAttributedString alloc] initWithHTML:bytes documentAttributes:nil]; // interpret as HTML
NSString *decoded = attributed.string; // and finally as plain text
return decoded;
}
That (a) strips the spaces, (b) creates a C string and (c) creates a byte buffer, all that so we can (d) interpret that byte buffer as HTML, and (e) finally gets the string back. The use of initWithBytesNoCopy:length:freeWhenDone: is to reduce the copying all this does.
Use it like:
NSString *raw = #"&# x62a;&# x631;&# x642;&# x628;";
NSString *decoded = [self decodeHTMLescapes:raw];
NSLog(#"%# -> %#", raw, decoded);
HTH

Ways to build NSStrings in Objective-C? [duplicate]

C# has syntax that allows you to specify the argument index in a string format specifier, e.g.:
string message = string.Format("Hello, {0}. You are {1} years old. How does it feel to be {1}?", name, age);
You can use arguments more than once and also omit arguments that are provided from being used. Another question mentions the same formatting for C/C++ in the form of %[index]$[format], e.g. %1$i. I have not been able to get NSString to fully respect this syntax, because it does behave well when omitting arguments from the format. The following does not work as expected (EXC_BAD_ACCESS because it attempts to dereference the age parameter as a NSObject*):
int age = 23;
NSString * name = #"Joe";
NSString * message = [NSString stringWithFormat:#"Age: %2$i", name, age];
The positional arguments are respected only if there are no missing arguments from the format (which seems to be an odd requirement):
NSString * message = [NSString stringWithFormat:#"Age: %2$i; Name: %1$#", name, age];
All these calls work properly in OS X:
printf("Age: %2$i", [name UTF8String], age);
printf("Age: %2$i %1$s", [name UTF8String], age);
Is there a way of accomplishing this using NSString in Objective-C / Cocoa? It would be useful for localization purposes.
NSString and CFString support reorderable/positional arguments.
NSString *string = [NSString stringWithFormat: #"Second arg: %2$#, First arg %1$#", #"<1111>", #"<22222>"];
NSLog(#"String = %#", string);
Also, see the documentation at Apple: String Resources
The following code fixes the bug specified in this issue. It is a workaround and renumbers the placeholders to fill gaps.
+ (id)stringWithFormat:(NSString *)format arguments:(NSArray*) arguments
{
NSMutableArray *filteredArguments = [[NSMutableArray alloc] initWithCapacity:arguments.count];
NSMutableString *correctedFormat = [[NSMutableString alloc ] initWithString:format];
NSString *placeHolderFormat = #"%%%d$";
int actualPlaceholderIndex = 1;
for (int i = 1; i <= arguments.count; ++i) {
NSString *placeHolder = [[NSString alloc] initWithFormat:placeHolderFormat, i];
if ([format rangeOfString:placeHolder].location != NSNotFound) {
[filteredArguments addObject:[arguments objectAtIndex:i - 1]];
if (actualPlaceholderIndex != i) {
NSString *replacementPlaceHolder = [[NSString alloc] initWithFormat:placeHolderFormat, actualPlaceholderIndex];
[correctedFormat replaceAllOccurrencesOfString:placeHolder withString:replacementPlaceHolder];
[replacementPlaceHolder release];
}
actualPlaceholderIndex++;
}
[placeHolder release];
}
if (filteredArguments.count == 0) {
//No numbered arguments found: just copy the original arguments. Mixing of unnumbered and numbered arguments is not supported.
[filteredArguments setArray:arguments];
}
NSString* result;
if (filteredArguments.count == 0) {
//Still no arguments: don't use initWithFormat in this case because it will crash: just return the format string
result = [NSString stringWithString:format];
} else {
char *argList = (char *)malloc(sizeof(NSString *) * [filteredArguments count]);
[filteredArguments getObjects:(id *)argList];
result = [[[NSString alloc] initWithFormat:correctedFormat arguments:argList] autorelease];
free(argList);
}
[filteredArguments release];
[correctedFormat release];
return result;
}
After doing more research, it appears Cocoa respects positional syntax in printf. Therefore an alternate pattern would be:
char msg[512] = {0};
NSString * format = #"Age %2$i, Name: %1$s"; // loaded from resource in practice
sprintf(msg, [format UTF8String], [name UTF8String], age);
NSString * message = [NSString stringWithCString:msg encoding:NSUTF8StringEncoding];
However, it would be nice if there was an implementation of this on NSString.

How to right pad a string using stringWithFormat

I would like to be able to right align a string using spaces. I have to be able to use the stringWithFormat: method.
So far I have tried the recommended format and it does not seem to work: [NSString stringWithFormat:#"%10#",#"test"].
I would expect this to return a string that has six spaces followed by "test" but all I am getting is "test" with no spaces.
It appears that stringWithFormat ignores the sizing requests of the %# format specifier. However, %s specifier works correctly:
NSString *test = #"test";
NSString *str = [NSString stringWithFormat:#"%10s", [test cStringUsingEncoding:NSASCIIStringEncoding]];
NSLog(#"'%#'", str);
This prints ' test'.
It's C style formatting. %nd means the width is n.
check following code.
NSLog(#"%10#",[NSString stringWithFormat:#"%10#",#"test"]);
NSLog(#"%#",[NSString stringWithFormat:#" %#",#"test"]);
NSLog(#"%10#", #"test");
NSLog(#"%10s", [#"test" cStringUsingEncoding:[NSString defaultCStringEncoding]]);
NSLog(#"%10d", 1);
NSString *str = #"test";
int padding = 10-[str length]; //6
if (padding > 0)
{
NSString *pad = [[NSString string] stringByPaddingToLength:padding withString:#" " startingAtIndex:0];
str = [pad stringByAppendingString:str];
}
NSLog(#"%#", str);

How to convert NData populated with hex values to NSString

I have a NSdata object that is populated with a bunch of information thats formated in hex.. I am trying to convert it into its proper string representation but am struggling to have any success.
One thing I have tried is to simply put it into a NSString and then NSLog it with a special character identifier thingy.. forgot the word (%02x), However to do this I am encoding it to NSUTF16.. which i dont want to do.. I mearly want to see exactly whats the data I am getting looks like as a NSString.
The reason I am doing this is because I am having some issues with my encoding later on in my code and im not sure if its because the data I am receiving is incorrect or me stuffing it up at some point when I am handling it.
Any help would be appreciated.
You can get a string representation of your NSData like so:
NSData *data = (your data)
NSString *string = [NSString stringWithCString:[data bytes] encoding:NSUTF8StringEncoding];
Does that answer your question?
Maybe I haven't understood, but something like this:
NSData *yourData;
NSLog(#"%#", [yourData description]);
doesn't fit your need?
Give this a try -
-(NSString*)hexToString:(NSData*)data{
NSString *hexString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (([hexString length] % 2) != 0)
return nil;
NSMutableString *string = [NSMutableString string];
for (NSInteger i = 0; i < [hexString length]; i += 2) {
NSString *hex = [hexString substringWithRange:NSMakeRange(i, 2)];
NSInteger decimalValue = 0;
sscanf([hex UTF8String], "%x", &decimalValue);
[string appendFormat:#"%d", decimalValue];
}
return string;
}

Resources