NSDecimalNumber and popping digits off of the end - iphone

I'm not quite sure what to call it, but I have a text field to hold a currency value, so I'm storing that as a NSDecimalNumber. I don't want to use the numbers & symbols keyboard so I'm using a number pad, and inferring the location of a decimal place like ATMs do. It works fine for entering numbers. Type 1234 and it displays $12.34 but now I need to implement back space. So assuming $12.34 is entered hitting back space would show $1.23. I'm not quite sure how to do this with a decimal number. With an int you would just divide by 10 to remove the right most digit, but that obviously doesn't work here. I could do it by some messy converting to int / 10 then back to decimal but that just sounds horrific... Any suggestions?

Call - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(id < NSDecimalNumberBehaviors >)behavior on it

How about using stringValue?
1) NSDecimalNumber to String
2) substring last
3) String to NSDecimalNumber
Below is an example for Swift 3
func popLastNumber(of number: NSDecimalNumber) -> NSDecimalNumber {
let stringFromNumber = number.stringValue //NSNumber property
let lastIndex = stringFromNumber.endIndex
let targetIndex = stringFromNumber.index(before: lastIndex)
let removed = stringFromNumber.substring(to: targetIndex)
return NSDecimalNumber(string: removed)
}
If your input number is a single digit, it would return NaN.
You could replace it to NSDecimalNumber.zero if you need.
It may works like delete button on calcultor.
It's not tested much.
If someone found another NaN case, please report by reply.

Related

How to align numbers vertically? Swift, UIKit

I want to align numbers by digits in table rows. For example:
___123.4
-5 678.9
That is, so that tens are under tens, units under units, a fractional number under a fractional number.
To convert a Number to a String, I use the numberStringFormatter function.
func numberStringFormat(_ number: Double) -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = 1
numberFormatter.groupingSeparator = " "
let result = numberFormatter.string(from: NSNumber(value: number))
return result ?? ""
}
This function sets the fractional format, determines the number of decimal places, and groups the numbers before the decimal point by digits.
But if the number is an integer, without fractions, or a digit after a floating point after rounding it turns out to be 0, then the formatted string looks like this, for example, 123
And then these numbers in the rows of the table are shifted and it turns out like this:
----123
5 678.9
That is, the fractional number on the bottom row is under the integer number on the top row.
In my opinion, I can solve this task if I force the Number to always show 0 after converting to a String.
I tried googling but couldn't find an answer to this question.
Maybe someone has already encountered such situations and can suggest a possible solution, or at least in what direction to move?
Or, perhaps there is some other solution without forcing 0 to be shown, but simply aligning the characters vertically?
Any ideas are welcome. I really appreciate your help.
Update: A greate solution from HangarRash.
minimumFractionDigits = 1

Number validation and formatting

I want to format, in real time, the number entered into a UITextField. Depending on the field, the number may be an integer or a double, may be positive or negative.
Integers are easy (see below).
Doubles should be displayed exactly as the user enters with three possible exceptions:
If the user begins with a decimal separator, or a negative sign followed by a decimal separator, insert a leading zero:
"." becomes "0."
"-." becomes "-0."
Remove any "excess" leading zeros if the user deletes a decimal point:
If the number is "0.00023" and the decimal point is deleted, the number should become "23".
Do not allow a leading zero if the next character is not a decimal separator:
"03" becomes "3".
Long story short, one and only one leading zero, no trailing zeros.
It seemed like the easiest idea was to convert the (already validated) string to a number then use format specifiers. I've scoured:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
and
http://www.cplusplus.com/reference/cstdio/printf/
and others but can't figure out how to format a double so that it does not add a decimal when there are no digits after it, or any trailing zeros. For example:
x = 23.0
print (String(format: "%f", x))
//output is 23.000000
//I want 23
x = 23.45
print (String(format: "%f", x))
//output is 23.450000
//I want 23.45
On How to create a string with format?, I found this gem:
var str = "\(INT_VALUE) , \(FLOAT_VALUE) , \(DOUBLE_VALUE), \(STRING_VALUE)"
print(str)
It works perfectly for integers (why I said integers are easy above), but for doubles it appends a ".0" onto the first character the user enters. (It does work perfectly in Playground, but not my program (why???).
Will I have to resort to counting the number of digits before and after the decimal separator and inserting them into a format specifier? (And if so, how do I count those? I know how to create the format specifier.) Or is there a really simple way or a quick fix to use that one-liner above?
Thanks!
Turned out to be simple without using NumberFormatter (which I'm not so sure would really have accomplished what I want without a LOT more work).
let decimalSeparator = NSLocale.current.decimalSeparator! as String
var tempStr: String = textField.text
var i: Int = tempStr.count
//remove leading zeros for positive numbers (integer or real)
if i > 1 {
while (tempStr[0] == "0" && tempStr[1] != decimalSeparator[0] ) {
tempStr.remove(at: tempStr.startIndex)
i = i - 1
if i < 2 {
break
}
}
}
//remove leading zeros for negative numbers (integer or real)
if i > 2 {
while (tempStr[0] == "-" && tempStr[1] == "0") && tempStr[2] != decimalSeparator[0] {
tempStr.remove(at: tempStr.index(tempStr.startIndex, offsetBy: 1))
i = i - 1
if i < 3 {
break
}
}
}
Using the following extension to subscript the string:
extension String {
subscript (i: Int) -> Character {
return self[index(startIndex, offsetBy: i)]
}
}

In Swift 3.0 How to make one character in a string move backward when you typing?

I am new in Swift.
I am trying to make a budget application. This app have a Calculator like keyboard. My idea is when users enter the money app will automatically add a decimal place for users.
For example, if you type 1230 it will give you 12.30 and type 123 it will display 1.23
I wrote a couple lines of code down below. The problem is it only can add decimal point after first digit it won't go backwards when you give more digits. It only can display as X.XXXXX
I tried solve this problem with String.index(maybe increase index?) and NSNumber/NSString format. But I don't know this is the right direction or not.
let number = sender.currentTitle!
let i: String = displayPayment.text!
if (displayPayment.text?.contains("."))!{
displayPayment.text = i == "0" ? number : displayPayment.text! + number
}
else {
displayPayment.text = i == "0" ? number : displayPayment.text! + "." + number
}
Indexing Strings in Swift is not as "straightforward" as many would like, simply due to how Strings are represented internally. If you just want to add a . at before the second to last position of the user input you could do it like this:
let amount = "1230"
var result = amount
if amount.characters.count >= 2 {
let index = amount.index(amount.endIndex, offsetBy: -2)
result = amount[amount.startIndex..<index] + "." + amount[index..<amount.endIndex]
} else {
result = "0.0\(amount)"
}
So for the input of 1230 result will be 12.30. Now You might want to adjust this depending on your specific needs. For example, if the user inputs 30 this code would result in .30 (this might or might not be what you want).

formatting NSDecimalNumber issue

I'm trying to create NSDecimalNumber with simply format like: 123.00 with two fractional digits after dot, always. I tried use the NSFormatter and many other ways like converting float from string and creating then NSDecimalNumber from this string, but it's not working.
The problem is that I need only NSDecimalNumber in this format, not NSString or any other.
Thanks for any advice,
Paul
You may get idea from this.
float num = 123.1254546;
NSString *str = [NSString stringWithFormat:#"%.2f",num];
NSLog(#"%.2f %#",num,str);
I think you simply need to do Type Casting operation for Two times as bellow
float value = 123.562;
int myDigit = value;
it gives value 123 in myDigit variable
NSLog(#"MyDigit in Decimal = %d",myDigit);
Output is MyDigit in Decimal = 123
now if you want output like 123.000 then simply write as bellow
float valueWithZiro = myDigit;
NSLog(#"MyDigit with 000 == %3f",valueWithZiro);
Output is MyDigit in Decimal = 123.000
NSDecimalNumber, like NSNumber, cannot contain formatting information. The object structure simply doesn't support it. It represents a number, not the way the number is displayed.
You can convert it to a formatted NSString (which you say you don't want). But you can't do what you're asking.
You convert it to a formatted NSString using an NSNumberFormatter. It's the object that allows you to specify the decimal and thousands separators, number of decimal places to display, the currency symbol, etc.
Maybe you were looking to store a NSNumberDecimal with just two digits after the fraction?
If so NSDecimalNumberBehaviors is your friend.
I had a similar need and used the following:
self.decimalHandlingBehaviorForApp = [NSDecimalNumberHandler
decimalNumberHandlerWithRoundingMode:NSRoundUp
scale:2 raiseOnExactness:NO
raiseOnOverflow:NO raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
Edit: added example of using it
// update the taxable total first
self.cartTaxableTotal = [self.cartTaxableTotal decimalNumberByAdding:itemAdded.priceOfItem
withBehavior:self.decimalHandlingBehaviorForApp];

Objective C - Adding characters at specific parts of a string

I have made a quadratic equation solver for the iPhone and when the text box is clicked, my own custom keypad appears. I have a button that changes whether the number is positive or negative. Right now I what happens is that when the button is pressed (0 - current value of text) is what is displayed in the text box, so if the number is positive, it will become negative and if it is negative it will become positive. I am having some problems doing this so what I wanted to is to put a minus sign at the beginning of the string if the number is positive and if the number is negative, the minus sign will be removed. Can anyone give me guidance on this?
Instead of negating using a mathematical function I assigned a NSMutableString to my UITextField then I inserted a "-" sign using insertString:atIndex: then I reassigned the changed string to my UITextField. To toggle between positive and negative, I created an if function so if the float value of my textfield is greater or equal to 0, then an "-" is inserted but if the float value of my text field is less than zero, the "-" is removed using deleteCharactersInRange. Here is my code as it stands:
- (IBAction)positivity{
NSMutableString *a = [NSMutableString stringWithString:aVal.text];
if([aVal.text floatValue]>=0){
[a insertString: #"-" atIndex: 0];
aVal.text = a;
}
else if([aVal.text floatValue]<0){
NSRange range = {0,1};
[a deleteCharactersInRange:range];
aVal.text = a;
}
}
aVal is the name of the UITextField that i am changing.
An alternative to the straight string approach is to not use a string. A while back I wrote a graphing calculator for iPhone that stored the equation internally in an NSMutableArray of NSStrings. Each slot in the array corresponded to one element in the equation, such as "x", "^", "sin(", etc.
When I needed to negate the equation, it was much easier to tell the array to insertObject:#"-" atIndex:0 than to try and insert it directly into the string. Then whenever the array was changed, I just remade the equation string like this:
NSString * newEquation = [equationElements componentsJoinedByString:#""];
While you could directly manipulate a string representation of a numeric value, such an approach is a bad idea. Not only is it less efficient than other alternatives, but potentially incorrect. (For example, #Ken's answer would result in two minus signs.)
What you probably want to do is negate the numeric value (just multiply it by -1, or subtract it from 0 as you suggested) and reflect that change in the interface (you mention a text box).
If you're using standard Cocoa controls (which inherit from NSControl, as NSTextField does) I suggest using -[NSControl setIntegerValue:] to change the text of the text field. If you (can) break up your UI well and have a text field for each variable in the quadratic equation, this should be fairly simple. (If you're using something other than an integer value, use something like -setDoubleValue: or -setFloatValue: instead.)
If you must create your own string beforehand, using an integer format specifier will display a "-" sign automatically if appropriate. Be sure to use %ld instead of %d (thanks, #Peter!) as the format specifier for NSInteger values to avoid possibly truncating values larger than 32-bit. For example:
NSString *result = [NSString stringWithFormat:#"%ld", nsIntegerValue];
In a more general sense, if you need to insert a dynamically-obtained string (not just something for which you can create a format string at compile time) you can also use an NSMutableString and its methods -appendString: and -insertString:atIndex: as well.