How to define a variable string format specifier - objective-c

I have this line of code
// valueX is a long double (long double is a huge floating point)
NSString *value = [NSString stringWithFormat: #"%.10Lg", valueX];
This format specifier is specifying up to 10 decimal digits but I don't want to hard code this to 10.
I have this variable numberOfDigits that I want to be used to define the number of digits. For those itching to down vote this question, it is not so easy as it seems. I cannot substitute the 10 with %# because %.10Lg is a format specifier by itself.
OK, I can create a bunch of strings like #"%.5Lg", #"%.8Lg", #"%.9Lg"... and switch that, but I wonder if there is another way...

There is, if you read the manual pages for format specifiers. You can replace the precision with *, which means it will get taken from a parameter instead.
int numDigits = 10;
NSString *value = [NSString stringWithFormat:#"%.*Lg", numDigits, valueX];
I couldn't find this in the core foundation reference, but I know that this is written in the man 3 printf man page.

Dietrich's answer is the simplest and therefore best. Note that even if there wasn't a built-in way to specify the number of digits with a parameter you could still have done it by first building your format string and then using it:
- (NSString *) stringFromValue: (long double) value digits: (int) digits; {
//First create a format string. Use "%%" to escape the % escape char.
NSString *formatString =[NSString stringWithFormat: #"%%.%dLg", digits];
return [NSString stringWithFormat: formatString, value];
}

Related

objective-c NSString to 0x%04x format

NSString *testValue = #"3141";
I want to convert "3141" to 0x0c45, use hexadecimal format(0x%04x).
like this:
printf("0x%04x", testValue);
The value printed out is:
0x0c45
But I don't know how to save it, how can I do it?
====================================================
NSString *testValue = #"3141";
NSUInteger unsignedValue = (NSUInteger)testValue.integerValue;
NSString *formatted = [NSString stringWithFormat:#"0x%04X", unsignedValue];
The result of this transfer seems to be incorrect. The result is 0x0000. Let me paste the source code as follows:
UInt16 myValue = 3141;
printf("0x%04x", myValue);
The result printed is 0x0c45. But what I need is not to print, but to save the value 0x0c45.
If you take a look at the parameters that printf expects, there's a table of format specifiers that printf understands, and the input that printf expects to correspond to those format specifiers. Specifically, the x/X specifiers:
converts an unsigned integer into hexadecimal representation hhhh
When printf tries to format testValue, it is expecting an unsigned integer of some variety (unsigned int, unsigned long, etc.), and the testValue you pass in is an NSString * (a pointer to an NSString). The pointer value itself is being interpreted as an unsigned integer, and printed out by printf.
In order to get printf to print the value you actually expect, you will first need to get the integer value of the string (either via integerValue, or a different method), and then pass that to printf. For example:
NSString *testValue = #"3141";
NSUInteger unsignedValue = (NSUInteger)testValue.integerValue;
printf("0x%04X", unsignedValue);
(Note that in a production environment, you'll probably want to use something more failure tolerant than just integerValue, and you'll need to be aware of the domain of how large testValue might need to be, the size of the storage of unsignedValue, etc.)
Update: If you'd like to get the result of formatting a value in this way beyond just printing it, you can use something like +[NSString stringWithFormat:] to get the string value. This method accepts the same specifiers that printf does, so you can use it in the same way:
NSString *testValue = #"3141";
NSUInteger unsignedValue = (NSUInteger)testValue.integerValue;
NSString *formatted = [NSString stringWithFormat:#"0x%04X", unsignedValue];
// Do anything you want with `formatted`.

How do I convert a decimal to hexadecimal using Objective C?

I've been working on a calculator and I wanted to implement conversions from decimal to octal and from decimal to hexadecimal. I'm new to Xcode and Objective C, but I've managed to get a conversion from decimal to octal, it just doesn't seem to work with hexadecimal.
Here's the code I've written to convert a double to octal:
double result = 0;
...
double decToOct = [self popOperand];
NSString *oct = [NSString stringWithFormat:#"%llo", (long long)decToOct];
result = [oct doubleValue];
Using the same scheme (obviously that includes changing #"%llo" with #"%llx") the conversion to hexadecimal works up to a certain point. It does numbers 0 through 9 just fine, but once it hits 10, it comes up as 0. To test, I also input 5395 and it displayed 1513, the desired result.
Because of this, I can only assume that for some reason my code does not want to input the actual letters of the hexadecimal values (e.g. 11 would convert to B but it shows up as 0) .
Any suggestions? Thanks in advance.
UPDATE:
In addition, I have also been using this to display the result:
double result = [self.brain performOperation:operation];
self.display.text = [NSString stringWithFormat:#"%g", result];
result, as listed from the top, is an argument which is eventually returned here, to self.brain performOperation:operation. This is supposed to handle the display of all operations, including: addition, multiplication, etc. but also octal and hexadecimal. Again, it works fine with octal, but not with hexadecimal.
Try this, May be it will help you. Please do let me know if i am wrong here:--->
NSString *decStr = #"11";
NSString *hexStr = [NSString stringWithFormat:#"%lX",
(unsigned long)[dec integerValue]];
NSLog(#"%#", hexStr);
If you know your string only contains a valid decimal number then the simplest way would be:
NSString *dec = #"254";
NSString *hex = [NSString stringWithFormat:#"0x%lX",
(unsigned long)[dec integerValue]];
NSLog(#"%#", hex);

What happened to Objective-C's "stringWithFormat:" method?

When I define
NSString *testString = [NSString stringWithFormat:#"%4d", 543210];
then testString is #"543210", instead of #"3210"
This used to work in Xcode v4.3.1 but now I upgraded to v4.6 and it stopped working.
Any ideas?
then testString is #"543210", instead of #"3210"
That's the correct behavior anyway. The %Nd format specifier doesn't limit the field with of the number being formatted - it only pads it with space if the field with is greater than the number of characters required to represent the number. If you got 3210 previously, that's erroneous.
If you want to format a number so at most its last four digits are printed, then you can do something like this:
NSString *numStr = [NSString stringWithFormat:#"%d", 543210]; // or whatever
if (numStr.length > 4) {
numStr = [numStr substringFromIndex:numStr.length - 4];
}
Another alternative, has the benefit of being short:
NSString *testString = [NSString stringWithFormat:#"%4d", 543210 % 10000];
The modulus operator % returns the remainder, so if you % 10000 you get the 4 least significant digits.

Dynamically format a float in a NSString

Consider this:
NSString *whatever=[NSString stringWithFormat:#"My float: %.2f",aFloat];
This will round my aFloat to 2 decimal places when building the string whatever
Suppose I want the 2 in this statement to be assignable, such that, based on the value of aFloat I might have it show 2 or 4 decimal places. How can I build this into stringWithFormat?
I want to be able to do this without an if that simply repeats the entire line for different cases, but rather somehow dynamically change just the %.2f portion.
The proper answer is to use an NSNumberFormatter.
However, the easy answer that uses format strings is to use the asterisk specifier. According to the Apple documentation the format string conforms to the IEEE printf specification. This specification states the following:
A field width, or precision, or both, may be indicated by an asterisk ( '*' ). In this case an argument of type int supplies the field width or precision.
This means that
int precision = 2;
NSString *whatever=[NSString stringWithFormat:#"My float: %.*f", precision,aFloat];
// Asterisk in place of 2^^ ^^^^^^^^^ int variable
should work. I have to say, I haven't tried it though, I tend to use NSNumberFormatters.
You will need to build the format first:
NSInteger precision = 2;
NSString *format = [#"My float: %." stringByAppendingFormat:#"%d", precision];
format = [format stringByAppendingString:#"f"];
NSString *whatever=[NSString stringWithFormat:format, aFloat];
Escape % as %% to build format strings:
NSUInteger digits = aFloat > 10.0f ? 2 : 4;
NSString *format = [NSString stringWithFormat:#"My float: %%.%if", digits];
NSString *whatever = [NSString stringWithFormat:format, aFloat];

Variable interpolation inside printf-style formatting functions

Is there a way to pass a variable for the floating point precision parameter in printf-style string formatting functions in Objective-C (or even C)? For example, in TCL and other scripting languages, I can do something like this:
set precision 2
puts [format "%${precision}f" 3.14159]
and the output will be, of course, 3.14. I would like to do something similar in Objective-C:
float precision = 2
NSString *myString = [NSString stringWithFormat:#".2f", 3.14159]
except that I would like to include precision as a variable. How can this be done?
Yes, the string format specifiers for printf, which are used by Cocoa for formatting, include a variable-precision specifier, * placed after the decimal point:
int precision = 3;
NSLog(#"%.*f", precision, 3.14159);
NSString *myString = [NSString stringWithFormat:#".*f", precision, 3.14159];
You can do it by making your format string a variable, and then passing that to stringWithFormat, like this:
float precision = 2;
NSString* formatString = [NSString stringWithFormat:#"%%.%df", precision];
NSString* myString = [NSString stringWithFormat:formatString, 3.14159];
The format string says you want a "%" symbol followed by a "." and then the value stored in the variable "precision" followed by "f".