Convert string fraction to decimal - iphone

I have a plist file that I am reading out a measurement, but some of the measurements are fractions such as 6 3/8". I formatted them that way because it's easier to find that on a tape measure than it is to find 6.375". My problem is now I want to do a conversion to metric on the fly and it isn't reading in the fraction part of the number. My current code is this.
cutoutLabel.text = [NSString stringWithFormat:#"%.2f mm. %#", [[[sizeDict valueForKey:Sub_Size] objectForKey:#"Cutout Dimensions"]floatValue] * 25.4, [temp objectAtIndex:2]];
Thanks.

That's what I ended up doing.
NSArray *temp = [[[sizeDict valueForKey:Sub_Size] objectForKey:#"Cutout Dimensions"] componentsSeparatedByString:#" "];
if ([temp count] > 2) {
NSArray *fraction = [[temp objectAtIndex:1]componentsSeparatedByString:#"/"];
convertedFraction = [[fraction objectAtIndex:0]floatValue]/[[fraction objectAtIndex:1]floatValue];
}

You can get the numerator and denominator as follows:
NSRange slashPos = [fraction.text rangeOfString:#"/"];
NSString * numerator = [fraction.text substringToIndex:slashPos.location];
NSString * denominator = [fraction.text substringFromIndex:slashPos.location+1];
You should take more care than this,
check that your range is of length 1 and make sure that the string has characters after the "/" character. But if you know you are feeding this code a fraction string it should work in your case
The idea is in place, but you will also need to apply the same logic first to separate the whole number from you fraction. Apply the same logic, searching for a #" " and then find the numerator and denominator

Building on Ian's answer and trying to be a little more complete (since his example was for a whole number and fractional part with an inch character (6 3/8"), I suggest the following method (it also works if there are spaces before the whole number:
// Convert a string consisting of a whole and fractional value into a decimal number
-(float) getFloatValueFromString: (NSString *) stringValue {
// The input string value has a format similar to 2 1/4". Need to remove the inch (") character and
// everything after it.
NSRange found = [stringValue rangeOfString: #"\""]; // look for the occurrence of the " character
if (found.location != NSNotFound) {
// There is a " character. Get the substring up to the "\"" character
stringValue = [stringValue substringToIndex: found.location];
}
// Now the input format looks something like 2 1/4. Need to convert this to a float value
NSArray *temp = [stringValue componentsSeparatedByString:#" "];
float convertedFraction = 0;
float wholeNumber = 0;
for (int i=0; i<[temp count]; i++) {
if ([[temp objectAtIndex:i] isEqualToString:#""]) {
continue;
}
NSArray *fraction = [[temp objectAtIndex:i]componentsSeparatedByString:#"/"];
if ([fraction count] > 1) {
convertedFraction = [[fraction objectAtIndex:0]floatValue]/[[fraction objectAtIndex:1]floatValue];
}
else if ([fraction count] == 1) {
wholeNumber = [[fraction objectAtIndex:0] floatValue];
}
}
convertedFraction += wholeNumber;
return convertedFraction;
}

Related

I am getting Expected identifier in Xcode

I'm making an app for iPhone using obj-c that finds side lengths and angles for triangles. Part of the app uses the Pythagorean Theorem.
NSNumber *pySidea = [NSNumber numberWithInteger:[[sideA text] integerValue]];
NSNumber *pySideb = [NSNumber numberWithInteger:[[sideB text] integerValue]];
NSNumber *pySidec = [NSNumber numberWithInteger:[[sideC text] integerValue]];
int pyAside = [pySidea intValue];
int pyBside = [pySideb intValue];
int pyCside = [pySidec intValue];
if ([aSide length] = 0) {
NSString *finalAnserc = [sqrtf(powf(pyAside, 2) + powf(pyBside, 2))];
sideCstring = #"_anserSidec";
}
sideA, sideB and sideC are the sides of a triangle using a text field. I don't get an error for any part except
if ([aSide length] = 0) {
NSString *finalAnserc = [sqrtf(powf(pyAside, 2) + powf(pyBside, 2))];
sideCstring = #"_anserSidec";
}
where I get "Expected identifier". Thanks for any help.
This line:
NSString *finalAnserc = [sqrtf(powf(pyAside, 2) + powf(pyBside, 2))];
Seems to be wanting to create a string, but doesn't do anything except some arithmetic inside square brackets, which isn't valid syntax. I think you want something like:
float answer = sqrtf(powf(pyAside, 2) + powf(pyBside, 2));
NSString *finalAnswer = [[NSNumber numberWithFloat:answer] stringValue];
Calling powf() to square a number is a bit heavy-handed, too. You could just write:
float answer = sqrtf(pyAside*pyAside + pyBside*pyBside);
As Nithin notes in his answer, you have a logical error with your if statement too - you want to be using == probably.
Check your 'if' condition , it should be if([aSide length] == 0)
Remember two equal (=) signs...

Regex pattern and/or NSRegularExpression a bit too slow searching over very large file, can it be optimized?

In an iOS framework, I am searching through this 3.2 MB file for pronunciations: https://cmusphinx.svn.sourceforge.net/svnroot/cmusphinx/trunk/pocketsphinx/model/lm/en_US/cmu07a.dic
I am using NSRegularExpression to search for an arbitrary set of words that are given as an NSArray. The search is done through the contents of the large file as an NSString. I need to match any word that appears bracketed by a newline and a tab character, and then grab the whole line, for example if I have the word "monday" in my NSArray I want to match this line within the dictionary file:
monday M AH N D IY
This line starts with a newline, the string "monday" is followed by a tab character, and then the pronunciation follows. The entire line needs to be matched by the regex for its ultimate output. I also need to find alternate pronunciations of the words which are listed as follows:
monday(2) M AH N D EY
The alternative pronunciations always begin with (2) and can go as high as (5). So I also search for iterations of the word followed by parentheses containing a single number bracketed by a newline and a tab character.
I have a 100% working NSRegularExpression method as follows:
NSArray *array = [NSArray arrayWithObjects:#"friday",#"monday",#"saturday",#"sunday", #"thursday",#"tuesday",#"wednesday",nil]; // This array could contain any arbitrary words but they will always be in alphabetical order by the time they get here.
// Use this string to build up the pattern.
NSMutableString *mutablePatternString = [[NSMutableString alloc]initWithString:#"^("];
int firstRound = 0;
for(NSString *word in array) {
if(firstRound == 0) { // this is the first round
firstRound++;
} else { // After the first iteration we need an OR operator first.
[mutablePatternString appendString:[NSString stringWithFormat:#"|"]];
}
[mutablePatternString appendString:[NSString stringWithFormat:#"(%#(\\(.\\)|))",word]];
}
[mutablePatternString appendString:#")\\t.*$"];
// This results in this regex pattern:
// ^((change(\(.\)|))|(friday(\(.\)|))|(monday(\(.\)|))|(saturday(\(.\)|))|(sunday(\(.\)|))|(thursday(\(.\)|))|(tuesday(\(.\)|))|(wednesday(\(.\)|)))\t.*$
NSRegularExpression * regularExpression = [NSRegularExpression regularExpressionWithPattern:mutablePatternString
options:NSRegularExpressionAnchorsMatchLines
error:nil];
int rangeLocation = 0;
int rangeLength = [string length];
NSMutableArray * matches = [NSMutableArray array];
[regularExpression enumerateMatchesInString:string
options:0
range:NSMakeRange(rangeLocation, rangeLength)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
[matches addObject:[string substringWithRange:result.range]];
}];
[mutablePatternString release];
// matches array is returned to the caller.
My issue is that given the big text file, it isn't really fast enough on the iPhone. 8 words take 1.3 seconds on an iPhone 4, which is too long for the application. Given the following known factors:
• The 3.2 MB text file has the words to match listed in alphabetical order
• The array of arbitrary words to look up are always in alphabetical order when they get to this method
• Alternate pronunciations start with (2) in parens after the word, not (1)
• If there is no (2) there won't be a (3), (4) or more
• The presence of one alternative pronunciation is rare, occurring maybe 1 time in 8 on average. Further alternate pronunciations are even rarer.
Can this method be optimized, either by improving the regex or some aspect of the Objective-C? I'm assuming that NSRegularExpression is already optimized enough that it isn't going to be worthwhile trying to do it with a different Objective-C library or in C, but if I'm wrong here let me know. Otherwise, very grateful for any suggestions on improving the performance. I am hoping to make this generalized to any pronunciation file so I'm trying to stay away from solutions like calculating the alphabetical ranges ahead of time to do more constrained searches.
****EDIT****
Here are the timings on the iPhone 4 for all of the search-related answers given by August 16th 2012:
dasblinkenlight's create NSDictionary approach https://stackoverflow.com/a/11958852/119717: 5.259676 seconds
Ωmega's fastest regex at https://stackoverflow.com/a/11957535/119717: 0.609593 seconds
dasblinkenlight's multiple NSRegularExpression approach at https://stackoverflow.com/a/11969602/119717: 1.255130 seconds
my first hybrid approach at https://stackoverflow.com/a/11970549/119717: 0.372215 seconds
my second hybrid approach at https://stackoverflow.com/a/11970549/119717: 0.337549 seconds
The best time so far is the second version of my answer. I can't mark any of the answers best, since all of the search-related answers informed the approach that I took in my version so they are all very helpful and mine is just based on the others. I learned a lot and my method ended up a quarter of the original time so this was enormously helpful, thank you dasblinkenlight and Ωmega for talking it through with me.
Since you are putting the entire file into memory anyway, you might as well represent it as a structure that is easy to search:
Create a mutable NSDictionary words, with NSString keys and NSMutableArray values
Read the file into memory
Go through the string representing the file line-by-line
For each line, separate out the word part by searching for a '(' or a '\t' character
Get a sub-string for the word (from zero to the index of the '(' or '\t' minus one); this is your key.
Check if the words contains your key; if it does not, add new NSMutableArray
Add line to the NSMutableArray that you found/created at the specific key
Once your are finished, throw away the original string representing the file.
With this structure in hand, you should be able to do your searches in time that no regex engine would be able to match, because you replaced a full-text scan, which is linear, with a hash look-up, which is constant-time.
** EDIT: ** I checked the relative speed of this solution vs. regex, it is about 60 times faster on a simulator. This is not at all surprising, because the odds are stacked heavily against the regex-based solution.
Reading the file:
NSBundle *bdl = [NSBundle bundleWithIdentifier:#"com.poof-poof.TestAnim"];
NSString *path = [NSString stringWithFormat:#"%#/words_pron.dic", [bdl bundlePath]];
data = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSMutableDictionary *tmp = [NSMutableDictionary dictionary];
NSUInteger pos = 0;
NSMutableCharacterSet *terminator = [NSMutableCharacterSet characterSetWithCharactersInString:#"\t("];
while (pos != data.length) {
NSRange remaining = NSMakeRange(pos, data.length-pos);
NSRange next = [data
rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]
options:NSLiteralSearch
range:remaining
];
if (next.location != NSNotFound) {
next.length = next.location - pos;
next.location = pos;
} else {
next = remaining;
}
pos += (next.length+1);
NSString *line = [data substringWithRange:next];
NSRange keyRange = [line rangeOfCharacterFromSet:terminator];
keyRange.length = keyRange.location;
keyRange.location = 0;
NSString *key = [line substringWithRange:keyRange];
NSMutableArray *array = [tmp objectForKey:key];
if (!array) {
array = [NSMutableArray array];
[tmp setObject:array forKey:key];
}
[array addObject:line];
}
dict = tmp; // dict is your NSMutableDictionary ivar
Searching:
NSArray *keys = [NSArray arrayWithObjects:#"sunday", #"monday", #"tuesday", #"wednesday", #"thursday", #"friday", #"saturday", nil];
NSMutableArray *all = [NSMutableArray array];
NSLog(#"Starting...");
for (NSString *key in keys) {
for (NSString *s in [dict objectForKey:key]) {
[all addObject:s];
}
}
NSLog(#"Done! %u", all.count);
Try this one:
^(?:change|monday|tuesday|wednesday|thursday|friday|saturday|sunday)(?:\([2-5]\))?\t.*$
and also this one (using positive lookahead with list of possible first letters):
^(?=[cmtwfs])(?:change|monday|tuesday|wednesday|thursday|friday|saturday|sunday)(?:\([2-5]\))?\t.*$
and at the end, a version with some optimization:
^(?=[cmtwfs])(?:change|monday|t(?:uesday|hursday)|wednesday|friday|s(?:aturday|unday))(?:\([2-5]\))?\t.*$
Here is my hybrid approach of dasblinkenlight's and Ωmega's answers, which I thought I should add as an answer as well at this point. It uses dasblinkenlight's method of doing a forward search through the string and then performs the full regex on a small range in the event of a hit, so it exploits the fact that the dictionary and words to look up are both in alphabetical order and benefits from the optimized regex. Wish I had two best answer checks to give out! This gives the correct results and takes about half of the time of the pure regex approach on the Simulator (I have to test on the device later to see what the time comparison is on the iPhone 4 which is the reference device):
NSMutableArray *mutableArrayOfWordsToMatch = [[NSMutableArray alloc] initWithArray:array];
NSMutableArray *mutableArrayOfUnfoundWords = [[NSMutableArray alloc] init]; // I also need to know the unfound words.
NSUInteger pos = 0;
NSMutableString *mutablePatternString = [[NSMutableString alloc]initWithString:#"^(?:"];
int firstRound = 0;
for(NSString *word in array) {
if(firstRound == 0) { // this is the first round
firstRound++;
} else { // this is all later rounds
[mutablePatternString appendString:[NSString stringWithFormat:#"|"]];
}
[mutablePatternString appendString:[NSString stringWithFormat:#"%#",word]];
}
[mutablePatternString appendString:#")(?:\\([2-5]\\))?\t.*$"];
// This creates a string that reads "^(?:change|friday|model|monday|quidnunc|saturday|sunday|thursday|tuesday|wednesday)(?:\([2-5]\))?\t.*$"
// We don't want to instantiate the NSRegularExpression in the loop so let's use a pattern that matches everything we're interested in.
NSRegularExpression * regularExpression = [NSRegularExpression regularExpressionWithPattern:mutablePatternString
options:NSRegularExpressionAnchorsMatchLines
error:nil];
NSMutableArray * matches = [NSMutableArray array];
while (pos != data.length) {
if([mutableArrayOfWordsToMatch count] <= 0) { // If we're at the top of the loop without any more words, stop.
break;
}
NSRange remaining = NSMakeRange(pos, data.length-pos);
NSRange next = [data
rangeOfString:[NSString stringWithFormat:#"\n%#\t",[mutableArrayOfWordsToMatch objectAtIndex:0]]
options:NSLiteralSearch
range:remaining
]; // Just search for the first pronunciation.
if (next.location != NSNotFound) {
// If we find the first pronunciation, run the whole regex on a range of {position, 500} only.
int rangeLocation = next.location;
int searchPadding = 500;
int rangeLength = searchPadding;
if(data.length - next.location < searchPadding) { // Only use 500 if there is 500 more length in the data.
rangeLength = data.length - next.location;
}
[regularExpression enumerateMatchesInString:data
options:0
range:NSMakeRange(rangeLocation, rangeLength)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
[matches addObject:[data substringWithRange:result.range]];
}]; // Grab all the hits at once.
next.length = next.location - pos;
next.location = pos;
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove the word.
pos += (next.length+1);
} else { // No hits.
[mutableArrayOfUnfoundWords addObject:[mutableArrayOfWordsToMatch objectAtIndex:0]]; // Add to unfound words.
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove from the word list.
}
}
[mutablePatternString release];
[mutableArrayOfUnfoundWords release];
[mutableArrayOfWordsToMatch release];
// return matches to caller
EDIT: here is another version which uses no regex and shaves a little bit more time off of the method:
NSMutableArray *mutableArrayOfWordsToMatch = [[NSMutableArray alloc] initWithArray:array];
NSMutableArray *mutableArrayOfUnfoundWords = [[NSMutableArray alloc] init]; // I also need to know the unfound words.
NSUInteger pos = 0;
NSMutableArray * matches = [NSMutableArray array];
while (pos != data.length) {
if([mutableArrayOfWordsToMatch count] <= 0) { // If we're at the top of the loop without any more words, stop.
break;
}
NSRange remaining = NSMakeRange(pos, data.length-pos);
NSRange next = [data
rangeOfString:[NSString stringWithFormat:#"\n%#\t",[mutableArrayOfWordsToMatch objectAtIndex:0]]
options:NSLiteralSearch
range:remaining
]; // Just search for the first pronunciation.
if (next.location != NSNotFound) {
NSRange lineRange = [data lineRangeForRange:NSMakeRange(next.location+1, next.length)];
[matches addObject:[data substringWithRange:NSMakeRange(lineRange.location, lineRange.length-1)]]; // Grab the whole line of the hit.
int rangeLocation = next.location;
int rangeLength = 750;
if(data.length - next.location < rangeLength) { // Only use the searchPadding if there is that much room left in the string.
rangeLength = data.length - next.location;
}
rangeLength = rangeLength/5;
int newlocation = rangeLocation;
for(int i = 2;i < 6; i++) { // We really only need to do this from 2-5.
NSRange morematches = [data
rangeOfString:[NSString stringWithFormat:#"\n%#(%d",[mutableArrayOfWordsToMatch objectAtIndex:0],i]
options:NSLiteralSearch
range:NSMakeRange(newlocation, rangeLength)
];
if(morematches.location != NSNotFound) {
NSRange moreMatchesLineRange = [data lineRangeForRange:NSMakeRange(morematches.location+1, morematches.length)]; // Plus one because I don't actually want the line break at the beginning.
[matches addObject:[data substringWithRange:NSMakeRange(moreMatchesLineRange.location, moreMatchesLineRange.length-1)]]; // Minus one because I don't actually want the line break at the end.
newlocation = morematches.location;
} else {
break;
}
}
next.length = next.location - pos;
next.location = pos;
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove the word.
pos += (next.length+1);
} else { // No hits.
[mutableArrayOfUnfoundWords addObject:[mutableArrayOfWordsToMatch objectAtIndex:0]]; // Add to unfound words.
[mutableArrayOfWordsToMatch removeObjectAtIndex:0]; // Remove from the word list.
}
}
[mutableArrayOfUnfoundWords release];
[mutableArrayOfWordsToMatch release];
Looking at the dictionary file you provided, I'd say that a reasonable strategy could be reading in the data and putting it into any sort of persistent data store.
Read through the file and create objects for each unique word, with n strings of pronunciations (where n is the number of unique pronunciations). The dictionary is already in alphabetical order, so if you parsed it in the order that you're reading it you'd end up with an alphabetical list.
Then you can do a binary search on the data - even with a HUGE number of objects a binary search will find what you're looking for very quickly (assuming alphabetical order).
You could probably even keep the whole thing in memory if you need lightning-fast performance.

Retrieve UITextfField values and convert to inches with decimal?

If I have formatting for a textfield like:
//Formats the textfield based on the pickers.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSString *result = [feetArray objectAtIndex:[feetPicker selectedRowInComponent:0]];
result = [result stringByAppendingFormat:#"%#ft", [feetArray objectAtIndex:[feetPicker selectedRowInComponent:1]]];
result = [result stringByAppendingFormat:#" %#", [inchArray objectAtIndex:[inchesPicker selectedRowInComponent:0]]];
result = [result stringByAppendingFormat:#"%#", [inchArray objectAtIndex:[inchesPicker selectedRowInComponent:1]]];
result = [result stringByAppendingFormat:#" %#in", [fractionArray objectAtIndex:[fractionPicker selectedRowInComponent:0]]];
myTextField.text = result;
}
Which display's in the textfield like 00ft 00 0/16in How can I change that all to inches with decimal? I'll need to take the ft, and multiply by 12 = variable.Then add that to inches, as well as take my fraction 1/16 and divide that by 16 to get my decimal value and then add that to the inches so it shows like 1234.0625 in order to make my calculation. Can someone help me accomplish this? Thank you in advance!
NSString * theString = RiseTextField.text;
NSString * feetString = [theString substringWithRange:NSMakeRange(0, 2)];
NSString * inchesString = [theString substringWithRange:NSMakeRange(5, 2)];
NSUInteger rangeLength = ([theString length] == 14) ? 1 : 2;
NSString * fractionString = [theString substringWithRange:NSMakeRange(8, rangeLength)];
double totalInInches = [feetString doubleValue] * 12 + [inchesString doubleValue] + [fractionString doubleValue] / 16;
You can easily get the number that you want by doing the calculations with the numbers you have there. Once you've got the actual number, you should use a NSNumberFormatter to present it with the desired amount of decimals and format.
This should solve your problem. Or did you need help converting the strings to numbers so that you can add them together?

How to know the length of NSString that fits a UILabel with fixed size?

I know NSString has methods that determine the frame size for it, using NSString UIKit Additions, sizeWithFont......
How about the other way around? I mean if I have a fixed frame size, how do I know how many characters or words for a NSString that can fit into it?
If I know this, I can cut off the NSString easily.
thanks
It might not be the most elegant solution, but you could do something like this:
- (NSString *)string:(NSString *)sourceString reducedToWidth:(CGFloat)width withFont:(UIFont *)font {
if ([sourceString sizeWithFont:font].width <= width)
return sourceString;
NSMutableString *string = [NSMutableString string];
for (NSInteger i = 0; i < [sourceString length]; i++) {
[string appendString:[sourceString substringWithRange:NSMakeRange(i, 1)]];
if ([string sizeWithFont:font].width > width) {
if ([string length] == 1)
return nil;
[string deleteCharactersInRange:NSMakeRange(i, 1)];
break;
}
}
return string;
}
Then call it like this:
NSString *test = #"Hello, World!";
CGFloat width = 40.0;
UIFont *font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
NSString *reducedString = [self string:test reducedToWidth:width withFont:font];
NSLog(#"%#", reducedString);
You cannot know/determine the number of characters that fits in a UILabel with fixed width because some characters are smaler than others, eg l and m.
There are two options:
Use Mono-Space-Fonts (each character has also a fixed width). Then determine the width for one char in your font with your font-size and calculate the number of chars
Allow any number of characters and check on insert if the inserted characters fit.
You have to know what behaviour you want to have. What should happen if there is text that does not fit. If you only want to truncate (like the solution of mortenfast does) then just use UILineBreakModeTailTruncation for the lineBreakMode-property of your UILabel (there are more options, like TruncateHead, Clip, Word Wrap)
Or you just just use the lineBreak property and set it to NSLineBreakByCharWrapping and move on with your life. https://stackoverflow.com/a/29088337/951349
Thanks #Morten. I've updated the sample code to handle word separation. It also eliminates extra spaces in between words. It has not been tested in the field, but my tests have, thus far, proven OK. Please update at your leisure if you find improvements or bug/glitch fixes.
-(NSString*)string:(NSString*)sourceString reducedToWidth:(CGFloat)width withFont:(UIFont*)font {
// if full string is within bounds, simply return the full string
if( [sourceString sizeWithFont:font].width <= width ) return sourceString;
// break up string into words. if <= 1 word, return original string
NSArray* words = [sourceString componentsSeparatedByString:#" "];
NSInteger numWords = [words count];
if( numWords <= 1 ) return sourceString;
// our return var. we populate as we go
NSMutableString* str = [NSMutableString string];
// temp var to test with before adding to return string
NSMutableString* strTemp = [NSMutableString string];
// string to hold word LESS spaces
NSString* strWordTemp = nil;
// the word we're currently on
NSInteger numWord = 0;
// whether we need to add a space (when not last word)
Boolean addSpace = NO;
// loop through our words....
for( NSString* strWord in words ) {
// which word we're on
numWord++;
// eliminate white space
strWordTemp = [strWord stringByReplacingOccurrencesOfString:#" " withString:#""];
// if this word is empty or was a space(s), skip it
if( [strWordTemp isEqualToString:#""] ) continue;
// append to temp string
[strTemp appendString:strWordTemp];
// if we're still within the bounds...
if( [strTemp sizeWithFont:font].width <= width ) {
// default = no extra space
addSpace = NO;
// if we're not the last word, add a space & check for length
if( numWord < numWords ) {
[strTemp appendString:#" "];
// if adding space made it too long, then just don't add it!
if( [strTemp sizeWithFont:font].width > width ) {
// it was too long with space, so we'll just add word
[str appendString:strWordTemp];
break;
}
// otherwise, it's OK to add the space
else addSpace = YES;
}
// append to return string and continue
[str appendFormat:#"%#%#", strWordTemp, ( addSpace ? #" " : #"" )];
}
// otherwise, we're done
else break;
}
// return our result
return str;
}

ObjC Formatting Decimal places of Float to string

How do I format a float to string so that if the user enters a number that has 2 or less decimal places then it is formatted to have 2 decimal places, but if the user enters a float that has 2 or more decimal places then all decimal places are shown. e.g.
4.1 => 4.10
1 => 1.00
1.358484 => 1.358484
So therefore the formatting is to 2 decimal places or more if needed.
Hope I made sense.
Try something like this.
BOOL requiresExtraPrecision (double num) {
double roundedToHundredth = round(num * 100.0) / 100.0;
double diff = num - roundedToHundredth;
if (diff < 0) diff = 0.0 - diff;
if (diff < 0.0000001) {
return NO;
} else {
return YES;
}
}
NSString *formatted (double num) {
if (requiresExtraPrecision(num)) {
return [NSString stringWithFormat:#"%F", num];
} else {
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setMaximumFractionDigits:2];
[formatter setMinimumFractionDigits:2];
return [formatter stringFromNumber:[NSNumber numberWithDouble:num]];
}
}
As #Carl wrote in a comment to the question, the hard part is deciding when a double needs all of its precision. In this code, I'm assuming that if the double is "close enough" to a rounded number (within a millionth), then we should just display the rounded number.
You might decide to make it stricter (a billionth?) but you'll always have to use some kind of approximation, because some decimals can't be stored precisely as a float. Even though the user may have typed "0.1" at input time, that information is lost when the number is stored as a float.
So, given that you'll have a float that's extremely close to a decimal but not exactly right, you'll have to decide when you think the float is "close enough" to the decimal.
If you need absolute precision (if you're working with money!) then you should consider using an NSDecimal or an NSDecimalNumber instead of a float.
this could work for you:
NSNumber *aFloat = [NSNumber numberWithFloat:1.2]; //try 1.234 ; 1.23 ; 1.2 ; 1. ; 1
NSString *numberString = [aFloat stringValue];
NSRange dot;
dot = [numberString rangeOfString:#"."];
NSString *finalString;
if (dot.location != NSNotFound) {
NSString *decimals = [numberString substringFromIndex:dot.location + dot.length];
if (decimals.length<1){ // ends with "."
finalString = [numberString stringByAppendingString:#"00"];
}else if (decimals.length<2){ // ends with ".n"
finalString = [numberString stringByAppendingString:#"0"];
}else { // 2 or more decimals: no changes
finalString = numberString;
}
}else { // no decimals
finalString = [numberString stringByAppendingString:#".00"];
}
NSLog(#"______._____finalString:%#", finalString );
EDIT (more flexible, it works with variable numbers of decimals):
NSNumber *aFloat = [NSNumber numberWithFloat:1.1235]; //try 1.234 ; 1.23 ; 1.2 ; 1. ; 1
NSString *numberString = [aFloat stringValue];
NSRange dot;
dot = [numberString rangeOfString:#"."];
if (dot.location == NSNotFound) { // no decimals, add a dot
numberString = [numberString stringByAppendingString:#"."];
NSLog(#"__added dot___ numberString:%#", numberString );
}
dot = [numberString rangeOfString:#"."];
NSString *decimals = [numberString substringFromIndex:dot.location + dot.length];
// int initialDecimals = decimals.length;
int numberOfDecimalsTerget = 2;
for (int initialDecimals = decimals.length; initialDecimals<numberOfDecimalsTerget; initialDecimals++) {
numberString = [numberString stringByAppendingString:#"0"];
}
NSLog(#"__END_._____numberString:%#", numberString );