Variable interpolation inside printf-style formatting functions - objective-c

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".

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 to define a variable string format specifier

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];
}

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];

Converting NSString to a decimal

I need to change the code below to make "intAmount" a decimal or an integer (i.e. a person can enter .10 or 1) in my uitextfield. The last line "myProduct" has to be a decimal not an integer and return the product in the format "18.00" for example. Can someone help someone help me alter my code snippit for this?
//amt has to be converted into a decimal value its a NSString now
NSInteger intAmount = [amt intValue];
//where total gets updated in the code with some whole (integer) value
NSInteger total=0;
//Change myProduct to a decimal with presicion of 2 (i.e. 12.65)
NSInteger myProduct=total*intAmount;
THIS DOESN'T WORK
NSDecimalNumber intAmount = [amt doubleValue];
//Keep in mind totalCost is an NSInteger
NSDecimalNumber total=totalCost*intAmount;
Use doubleValue instead of intValue to get the correct fractional number out of your text field. Put it in a variable of type double rather than NSInteger. Then use the format %.2g when you print it out and it will look like you want it to.
If you need to track decimal values explicitly, you can use NSDecimalNumber. However, if all you're doing is this one operation, Carl's solution is most likely adequate.
If you have a string representation of a real number (non-integer), you can use an NSScanner object to scan it into a double or float, or even an NSDecimal structure if that is your true intention (the NSDecimal struct and NSDecimalNumber class are useful for containing numbers that can be exactly represented in decimal).
NSString *amt = #"1.04";
NSScanner *aScanner = [NSScanner localizedScannerWithString:amt];
double theValue;
if ([aScanner scanDouble:&theValue])
{
// theValue should equal 1.04 (or thereabouts)
}
else
{
// the string could not be successfully interpreted
}
The benefit to using a localised NSScanner object is that the number is interpreted based on the user's locale, because “1.000” could mean either one-thousand or just one, depending on your locale.

How to convert a string into double and vice versa?

I want to convert a string into a double and after doing some math on it, convert it back to a string.
How do I do this in Objective-C?
Is there a way to round a double to the nearest integer too?
You can convert an NSString into a double with
double myDouble = [myString doubleValue];
Rounding to the nearest int can then be done as
int myInt = (int)(myDouble + (myDouble>0 ? 0.5 : -0.5))
I'm honestly not sure if there's a more streamlined way to convert back into a string than
NSString* myNewString = [NSString stringWithFormat:#"%d", myInt];
To really convert from a string to a number properly, you need to use an instance of NSNumberFormatter configured for the locale from which you're reading the string.
Different locales will format numbers differently. For example, in some parts of the world, COMMA is used as a decimal separator while in others it is PERIOD — and the thousands separator (when used) is reversed. Except when it's a space. Or not present at all.
It really depends on the provenance of the input. The safest thing to do is configure an NSNumberFormatter for the way your input is formatted and use -[NSFormatter numberFromString:] to get an NSNumber from it. If you want to handle conversion errors, you can use -[NSFormatter getObjectValue:forString:range:error:] instead.
Adding to olliej's answer, you can convert from an int back to a string with NSNumber's stringValue:
[[NSNumber numberWithInt:myInt] stringValue]
stringValue on an NSNumber invokes descriptionWithLocale:nil, giving you a localized string representation of value. I'm not sure if [NSString stringWithFormat:#"%d",myInt] will give you a properly localized reprsentation of myInt.
Here's a working sample of NSNumberFormatter reading localized number String (xCode 3.2.4, osX 10.6), to save others the hours I've just spent messing around. Beware: while it can handle trailing blanks such as "8,765.4 ", this cannot handle leading white space and this cannot handle stray text characters. (Bad input strings: " 8" and "8q" and "8 q".)
NSString *tempStr = #"8,765.4";
// localization allows other thousands separators, also.
NSNumberFormatter * myNumFormatter = [[NSNumberFormatter alloc] init];
[myNumFormatter setLocale:[NSLocale currentLocale]]; // happen by default?
[myNumFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
// next line is very important!
[myNumFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; // crucial
NSNumber *tempNum = [myNumFormatter numberFromString:tempStr];
NSLog(#"string '%#' gives NSNumber '%#' with intValue '%i'",
tempStr, tempNum, [tempNum intValue]);
[myNumFormatter release]; // good citizen
olliej's rounding method is wrong for negative numbers
2.4 rounded is 2 (olliej's method gets this right)
−2.4 rounded is −2 (olliej's method returns -1)
Here's an alternative
int myInt = (int)(myDouble + (myDouble>0 ? 0.5 : -0.5))
You could of course use a rounding function from math.h
// Converting String in to Double
double doubleValue = [yourString doubleValue];
// Converting Double in to String
NSString *yourString = [NSString stringWithFormat:#"%.20f", doubleValue];
// .20f takes the value up to 20 position after decimal
// Converting double to int
int intValue = (int) doubleValue;
or
int intValue = [yourString intValue];
For conversion from a number to a string, how about using the new literals syntax (XCode >= 4.4), its a little more compact.
int myInt = (int)round( [#"1.6" floatValue] );
NSString* myString = [#(myInt) description];
(Boxes it up as a NSNumber and converts to a string using the NSObjects' description method)
For rounding, you should probably use the C functions defined in math.h.
int roundedX = round(x);
Hold down Option and double click on round in Xcode and it will show you the man page with various functions for rounding different types.
This is the easiest way I know of:
float myFloat = 5.3;
NSInteger myInt = (NSInteger)myFloat;
from this example here, you can see the the conversions both ways:
NSString *str=#"5678901234567890";
long long verylong;
NSRange range;
range.length = 15;
range.location = 0;
[[NSScanner scannerWithString:[str substringWithRange:range]] scanLongLong:&verylong];
NSLog(#"long long value %lld",verylong);
convert text entered in textfield to integer
double mydouble=[_myTextfield.text doubleValue];
rounding to the nearest double
mydouble=(round(mydouble));
rounding to the nearest int(considering only positive values)
int myint=(int)(mydouble);
converting from double to string
myLabel.text=[NSString stringWithFormat:#"%f",mydouble];
or
NSString *mystring=[NSString stringWithFormat:#"%f",mydouble];
converting from int to string
myLabel.text=[NSString stringWithFormat:#"%d",myint];
or
NSString *mystring=[NSString stringWithFormat:#"%f",mydouble];
I ended up using this handy macro:
#define STRING(value) [#(value) stringValue]