Formatting a string containing a number with comma separation - iphone

I have a number stored in an NSMutableString instance which I want to auto format with comma delimiters and then display the result in a UITextField.
I've tried using NSNumberFormatter to format as currency, but I don't want it to show decimals if the original NSMutableString doesn't contain a decimal place.
For example:
If the NSMutableString contains "1234567", it should format as "1,234,567".
If the NSMutableString contains "1234567.1", it should format as "1,234,567.1"
If the NSMutableString contains "1234567.12", it should format as "1,234,567.12"
The maximum decimals that the NSMutableString will contain is 2.
Any help is greatly appreciated.
Thanks!

Keep in mind that you should really be localizing this if you are interacting with users on this, however here is one way to do it:
- (NSString *)formatString:(NSString *)string {
// Strip out the commas that may already be here:
NSString *newString = [string stringByReplacingOccurrencesOfString:#"," withString:#""];
if ([newString length] == 0) {
return nil;
}
// Check for illegal characters
NSCharacterSet *disallowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789."] invertedSet];
NSRange charRange = [newString rangeOfCharacterFromSet:disallowedCharacters];
if ( charRange.location != NSNotFound) {
return nil;
}
// Split the string into the integer and decimal portions
NSArray *numberArray = [newString componentsSeparatedByString:#"."];
if ([numberArray count] > 2) {
// There is more than one decimal point
return nil;
}
// Get the integer
NSString *integer = [numberArray objectAtIndex:0];
NSUInteger integerDigits = [integer length];
if (integerDigits == 0) {
return nil;
}
// Format the integer.
// You can do this by first converting to a number and then back to a string,
// but I would rather keep it as a string instead of doing the double conversion.
// If performance is critical, I would convert this to a C string to do the formatting.
NSMutableString *formattedString = [[NSMutableString alloc] init];
if (integerDigits < 4) {
[formattedString appendString:integer];
} else {
// integer is 4 or more digits
NSUInteger startingDigits = integerDigits % 3;
if (startingDigits == 0) {
startingDigits = 3;
}
[formattedString setString:[integer substringToIndex:startingDigits]];
for (NSUInteger index = startingDigits; index < integerDigits; index = index + 3) {
[formattedString appendFormat:#",%#", [integer substringWithRange:NSMakeRange(index, 3)]];
}
}
// Add the decimal portion if there
if ([numberArray count] == 2) {
[formattedString appendString:#"."];
NSString *decimal = [numberArray objectAtIndex:1];
if ([decimal length] > 0) {
[formattedString appendString:decimal];
}
}
return formattedString;
}
// Test cases:
NSLog(#"%#", [self formatString:#"123456"]);
NSLog(#"%#", [self formatString:#"1234567."]);
NSLog(#"%#", [self formatString:#"12345678.1"]);
NSLog(#"%#", [self formatString:#"123456789.12"]);
// Output:
123,456
1,234,567.
12,345,678.1
123,456,789.12

I think this should do it -- I added an if statement to check if there is a decimal point in the typed in value. "Output" in this example is a property that I have bound to the value of a text field to show the result.
-(IBAction)doConversion:(id)sender{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init];
[formatter setMaximumFractionDigits:2];
[formatter setUsesGroupingSeparator:YES];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
double entryFieldFloat = [entryField doubleValue];
if ([entryField.stringValue rangeOfString:#"."].length == 1) {
formatter.alwaysShowsDecimalSeparator = YES;
self.output =[formatter stringFromNumber:[NSNumber numberWithDouble:entryFieldFloat]];
}else{
formatter.alwaysShowsDecimalSeparator = NO;
self.output =[formatter stringFromNumber:[NSNumber numberWithDouble:entryFieldFloat]];
}
}

Just call this method to be simple:
public static String GetCommaSeparatedCount(this Int32 Count)
{
// Check for The less-than character (<) is converted to <
String result = String.Format("{0:#,##0}", Count);
return result;
}

You're looking for the -setMinimumFractionDigits: method on NSNumberFormatter. Set that to 0 and it'll only display the decimal point if there's anything to put after it.

Related

NSString to int issue

When I want to convert NSString to int
I use:
[string intValue];
But how to determine if string is int value? for instance to avoid situations like this:
[#"hhhuuukkk" intValue];
int value;
NSString *s = #"huuuk";
if([[NSScanner scannerWithString:s] scanInt:&value]) {
//Is int value
}
else {
//Is not int value
}
Edit: added isAtEnd check according to Martin R's suggestion. This will make sure it is only digits in the whole string.
int value;
NSString *s = #"huuuk";
NSScanner *scanner = [NSScanner scannerWithString:s];
if([scanner scanInt:&value] && [scanner isAtEnd]) {
//Is int value
}
else {
//Is not int value
}
The C way: use strtol() and check errno:
errno = 0;
int n = strtol(str.UTF8String, NULL, 0);
if (errno != 0) {
perror("strtol");
// or handle error otherwise
}
The Cocoa way: use NSNumberFormatter:
NSNumberFormatter *fmt = [[NSNumberFormatter alloc] init];
[fmt setGeneratesDecimalNumbers:NO];
NSNumber *num = nil;
NSError *err = nil;
NSRange r = NSMakeRange(0, str.length);
[fmt getObjectValue:&num forString:str range:&r error:&err];
if (err != nil) {
// handle error
} else {
int n = [num intValue];
}
NSString *yourStr = #"hhhuuukkk";
NSString *regx = #"(-){0,1}(([0-9]+)(.)){0,1}([0-9]+)";
NSPredicate *chekNumeric = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regx];
BOOL isNumber = [chekNumeric evaluateWithObject:yourStr];
if(isNumber)
{
// Your String has only numeric value convert it to intger;
}
else
{
// Your String has NOT only numeric value also others;
}
For only integer value change Rgex pattern to ^(0|[1-9][0-9]*)$ ;
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * amt = [f numberFromString:#"STRING"];
if(amt)
{
// convert to int if you want to like you have done in your que.
//valid amount
}
else
{
// not valid
}
NSString *stringValue = #"hhhuuukkk";
if ([[NSScanner scannerWithString:stringValue] scanInt:nil]) {
//Is int value
}
else{
//Is not int value
}
[[NSScanner scannerWithString:stringValue] scanInt:nil] will check if "stringValue" has an integer value.
It returns a BOOL indicating whether or not it found a suitable int value.

Formatting TextField text as Price

I want to format the textfield text when user enter a value .. It work perfectly but my problem is ,If user press 1 then 2 after that decimale point . My replacement string is "12." At that time numbar is 12 . i am not able to take decimal point ..
NSNumber* number = [numberFormatter numberFromString:string];
Here is My full code,
#pragma mark textfieldDelgate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSLocale *locale=[[NSLocale alloc]initWithLocaleIdentifier:#"en_GB"];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setLocale:locale];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *text = [textField text];
NSString *replacementText = [text stringByReplacingCharactersInRange:range withString:string];
NSMutableString *newReplacement = [[ NSMutableString alloc ] initWithString:replacementText];
NSString *currencyGroupingSeparator = numberFormatter.currencyGroupingSeparator;
[newReplacement replaceOccurrencesOfString:currencyGroupingSeparator withString:#"" options:NSBackwardsSearch range:NSMakeRange(0, [newReplacement length])];
NSNumber * number = [numberFormatter numberFromString:newReplacement];
if (number == nil && [replacementText length]!=0) {
return NO;
}
NSLog(#"%#",newReplacement);
text = [numberFormatter stringFromNumber:number];
[textField setText:text];
return NO;
}
I have also attached screenshot.
How can I format the string with decimal value......
Thanks in advance
For me the line of code:
NSNumber * number = [numberFormatter numberFromString:newReplacement];
does not returns nil but it removes the decimal entered by user. This is because with numberFormatter id you pass a value like '12.' or '12.0' it will remove the decimal as a part of formatting. For other values like 12.3 it will not remove decimal.
I am not able to understand your requirement for doing all this coding but if you want decimal to be there put some logic to check if number is in format of 12. or 12.0 , then escape formatting. Decimal will remain there.
Please use this code:
NSNumber * number;
if ([newReplacement hasSuffix:#"."] || [newReplacement hasSuffix:#".0"])
{
[textField setText:newReplacement]; return NO;
}
else
{
number = [numberFormatter numberFromString:newReplacement];
}
You'll probably want to use NSNumberFormatterCurrencyStyle instead of NSNumberFormatterDecimalStyle if you're dealing with formatting money. It might Just Work™ after setting that.
But, it might not. Regardless of all that, pretty sure the reason for the behavior you're seeing is that you're not giving it a number from your string; 12 is a number, as is 12.5, but, 12. is not. I'm surprised its not returning nil outright.
If thats the case (and its still broken), than you'll probably want to special-case having the . at the end, and append instead of passing it into the number formatter.
I have tried printing your code in my log. It is working fine for me.I think there is some other type of issue.
NSLocale *locale=[[NSLocale alloc]initWithLocaleIdentifier:#"en_GB"];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setLocale:locale];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber* number = [numberFormatter numberFromString:#"12.4"];
NSLog(#"number is %#",number);
log print-----
number is 12.4
//Add this in .h file
NSNumberFormatter *formatter;
NSInteger currencyScale;
NSString *enteredDigits;
//Add this in .m file`enter code here`
-(void)viewdidload
{
NSNumberFormatter *aFormatter = [[NSNumberFormatter alloc] init];
[aFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
currencyScale = -1 * [aFormatter maximumFractionDigits];
self.formatter = aFormatter;
}
#pragma UItextfield Delegate
- (void)textFieldDidBeginEditing:(UITextField *)textField {
// Keep a pointer to the field, so we can resign it from a toolbar
Field = textField;
if(textField.text==NULL || [textField.text isEqualToString:#""])
{
self.enteredDigits = #"";
//textField.text=#"";
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { //give tag to text field
if (textField.tag==10) {
// self.priceInput = textField;
// Check the length of the string
int len=[self.enteredDigits length];
NSLog(#"string lenght is %d",len);
if ([string length]) {
self.enteredDigits = [self.enteredDigits stringByAppendingFormat:#"%d", [string integerValue]];
} else {
// This is a backspace
NSUInteger len = [self.enteredDigits length];
if (len > 1) {
self.enteredDigits = [self.enteredDigits substringWithRange:NSMakeRange(0, len - 1)];
} else {
self.enteredDigits = #"";
}
}
NSDecimalNumber *decimal = nil;
if ( ![self.enteredDigits isEqualToString:#""]) {
decimal = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale];
float deci= [decimal floatValue];
NSLog(#"decimall==%f",deci);
} else {
decimal = [NSDecimalNumber zero];
}
// Replace the text with the localized decimal number
float deci= [decimal floatValue];
NSLog(#"decimall==%f",deci);
NSString *temp = [self.formatter stringFromNumber:decimal];
textField.text=temp;
//NSLog(#"Text fielddddddddddddddf=%# %#",numberText,temp);
return NO;
}
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
textField.text=#"";
self.enteredDigits=#"";
NSLog(#"Clear Clicked");
return YES;
}
I think this code will help you

How can i remove all emojs from a NSString

I need to remove all emoijs from a NSString.
So far i am using this NSString extension ...
- (NSString*)noEmoticon {
static NSMutableCharacterSet *emoij = NULL;
if (emoij == NULL) {
emoij = [[NSMutableCharacterSet alloc] init];
// unicode range of old emoijs
[emoij removeCharactersInRange:NSMakeRange(0xE000, 0xE537 - 0xE000)];
}
NSRange range = [self rangeOfCharacterFromSet:emoij];
if (range.length == 0) {
return self;
}
NSMutableString *cleanedString = [self mutableCopy];
while (range.length > 0) {
[cleanedString deleteCharactersInRange:range];
range = [cleanedString rangeOfCharacterFromSet:emoij];
}
return cleanedString;
}
... but that does not work at all. The range.length is always 0.
So the general question is : How can i remove a range of unicode characters from a NSString?
Thanks a lot.
It seems to me that in the above code the emoij variable is eventually an empty set. Didn't you mean to addCharactersInRange: rather than to removeCharactersInRange:?

Checking input value

I am trying to check whether the user gives an input that is number but not letters. When a non-numeric value is given I want to print an alert error message like "incorrect format".
This is my source code:
-(IBAction)btnPressed{
NSString *firstString = textFiled1.text;
NSString *secondString = textFiled2.text;
NSString *thirdString = textFiled3.text;
int num1;
int num2;
int num3;
int output;
num1 = [firstString intValue];
num2 = [secondString intValue];
num3 = [thirdString intValue];
output = (num1 + num2) / num3;
lable1.text = [NSString stringWithFormat:#"%d",output];
}
Use NSNumberFormatter. If the input parameter is not a valid number, the number derived will be nil.
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
num1 = [f numberFromString:firstString];
[f release];
if (num1 == nil) {
// throw exception
}
This is how I would do it:
NSCharacterSet *nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([firstString rangeOfCharacterFromSet:nonNumbers].location != NSNotFound) {
// firstString has non-number characters in it!
}

NSString range of string at occurrence

i'm trying to build a function that will tell me the range of a string at an occurrence.
For example if I had the string "hello, hello, hello", I want to know the range of hello at it's, lets say, third occurrence.
I've tried building this simple function, but it doesn't work.
Note - the top functions were constructed at an earlier date and work fine.
Any help appreciated.
- (NSString *)stringByTrimmingString:(NSString *)stringToTrim toChar:(NSUInteger)toCharacterIndex {
if (toCharacterIndex > [stringToTrim length]) return #"";
NSString *devString = [[[NSString alloc] init] autorelease];
for (int i = 0; i <= toCharacterIndex; i++) {
devString = [NSString stringWithFormat:#"%#%#", devString, [NSString stringWithFormat:#"%c", [stringToTrim characterAtIndex:(i-1)]]];
}
return devString;
[devString release];
}
- (NSString *)stringByTrimmingString:(NSString *)stringToTrim fromChar:(NSUInteger)fromCharacterIndex {
if (fromCharacterIndex > [stringToTrim length]) return #"";
NSString *devString = [[[NSString alloc] init] autorelease];
for (int i = (fromCharacterIndex+1); i <= [stringToTrim length]; i++) {
devString = [NSString stringWithFormat:#"%#%#", devString, [NSString stringWithFormat:#"%c", [stringToTrim characterAtIndex:(i-1)]]];
}
return devString;
[devString release];
}
- (NSRange)rangeOfString:(NSString *)substring inString:(NSString *)string atOccurence:(int)occurence {
NSString *trimmedString = [inString copy]; //We start with the whole string.
NSUInteger len, loc, oldLength;
len = 0;
loc = 0;
NSRange tempRange = [string rangeOfString:substring];
len = tempRange.length;
loc = tempRange.location;
for (int i = 0; i != occurence; i++) {
NSUInteger endOfWord = len+loc;
trimmedString = [self stringByTrimmingString:trimmedString fromChar:endOfWord];
oldLength += [[self stringByTrimmingString:trimmedString toChar:endOfWord] length];
NSRange tmp = [trimmedString rangeOfString:substring];
len = tmp.length;
loc = tmp.location + oldLength;
}
NSRange returnRange = NSMakeRange(loc, len);
return returnRange;
}
Instead of trimming the string a bunch of times (slow), just use rangeOfString:options:range:, which searches only within the range passed as its third argument. See Apple's documentation.
So try:
- (NSRange)rangeOfString:(NSString *)substring
inString:(NSString *)string
atOccurence:(int)occurence
{
int currentOccurence = 0;
NSRange rangeToSearchWithin = NSMakeRange(0, string.length);
while (YES)
{
currentOccurence++;
NSRange searchResult = [string rangeOfString: substring
options: NULL
range: rangeToSearchWithin];
if (searchResult.location == NSNotFound)
{
return searchResult;
}
if (currentOccurence == occurence)
{
return searchResult;
}
int newLocationToStartAt = searchResult.location + searchResult.length;
rangeToSearchWithin = NSMakeRange(newLocationToStartAt, string.length - newLocationToStartAt);
}
}
You need to rework the whole code. While it may seem to work, it's poor coding and plain wrong, like permanently reassigning the same variable, initializing but reassigning one line later, releasing after returning (which will never work).
For your question: Just use rangeOfString:options:range:, and do this the appropriate number of times while just incrementing the starting point.