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

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

Related

how can I assign the same random number to 2 variables in swift?

I am building an app that the user selects a multiplication table. Then it gives random numbers to multiplicate with the number they select. for example, if the user selects "1". the questions shown would be "1 x 1", or "1 x 8".
The problem is that I need to assign the same random number to 2 variables. The one that will be shown on the question and the one used to calculate the result.
I thought of something like this, but the random number is different on each variable. What can I do to use the same random number generated on 2 variables?
func game() -> (String, Int) {
let randomNumber = multiplicate.randomElement()
switch selectedQuestion {
case 0:
return ("1 × \(randomNumber!)", 1 * randomNumber!)
default:
return ("", 0)
}
}
Not exactly sure what you're asking but you could do something like this:
let number = Int.random(in: 0..<10)
let number2 = number
but I don't think there is a need to create a new variable for this. The whole idea of variables is that you can save some value and then use it later so there isn't really a need to create number2 here.

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

Swift: how to change a integer variable name within a method and reassign its value

I am a complete beginner at Swift/programming and am making a noughts and crosses app as part of an online course. I wanted to do this on my own before I saw the solution so my logic may be a bit weird.
I have a function which is called each time a button is pressed (there are 9, one for each square). The function acts to:
i) update the number of turns (which allows me to see who's go it is)
ii) change the picture to X or O
iii) deactivate the button after each turn
iv) calculate is anyone has won by changing the value of that squares potential lines. The numbers I have chosen to do this are 3 and 4 (for noughts and crosses), hence the c = 3 or 4 below. This means that if any winning line adds up to 9 or 12, the game stops as someone has won.
I have 9 variables (Int) that hold the score for each square - they are a1o, a2o, a3o, b1o... i.e all end in "o". In the function I want to add the string of "a1" in front of the "o", meaning each button is only relevant to itself with only one line of code above the function (within the button parentheses).
The function looks like this at the moment; calling it by: button(a1, buttonValue: "a1")
func button(buttonName: UIButton, buttonValue: NSString) -> String {
let a = buttonName
var b = buttonValue
b = (b as String) + "o"
print(b)
// the above prints "a1o", the name of the variable, but it is a string...
index += 1
print("Go number \(index)")
if index % 2 == 0 {
// show a nought
a.setImage(UIImage(named: "nought.png"), forState: UIControlState.Normal)
c = 3
// the above line doesn't work as its a string, but I am attempting to set the squares value to 3 (i.e. a1o = 3)
winner()
a.userInteractionEnabled = false
} else {
// show a cross
a.setImage(UIImage(named: "cross.png"), forState: UIControlState.Normal)
c = 4
// the above line doesn't work as its a string
winner()
a.userInteractionEnabled = false
}
return "done"
}
What I can't figure out is how to change the common stem of the variable *a1*o by not making it a string, or if I do, how I convert it back to a variable.
I am struggling with definitions and as a result looking for an answer has been hard. The variable a1o is an integer, but how do I refer to a1o itself?
Thank you in advance,
Sam
It is not possible to access variables dynamically by name like you want to do. However, there are better ways to accomplish the same goal. How about a two-dimensional array?
var scores: [[Int]] = [[0,0,0], [0,0,0], [0,0,0]]
scores[0][1] = 4 //this is the new version of "a2o = 4"
Unlike with variable names, the indices to the array ("0" and "1" in this case) can be dynamically chosen. Or, if you really want to keep your buttons' values exactly the same, you could use a dictionary:
var scores: [String: Int] = [:]
scores[buttonValue as String] = 4

Removing Digits from a Number

Does anybody know if there is a way of removing (trimming) the last two digits or first two digits from a number. I have the number 4131 and I want to separate that into 41 and 31, but after searching the Internet, I've only managed to find how to remove characters from a string, not a number. I tried converting my number to a string, then removing characters, and then converting it back to a number, but I keep receiving errors.
I believe I will be able to receive the first two digit by dividing the number by 100 and then rounding the number down, but I don't have an idea of how to get the last two digits?
Does anybody know the function to use to achieve what I'm trying to do, or can anybody point me in the right direction.
Try this:
var num = 1234
var first = num/100
var last = num%100
The playground's output is what you need.
You can use below methods to find the last two digits
func getLatTwoDigits(number : Int) -> Int {
return number%100; //4131%100 = 31
}
func getFirstTwoDigits(number : Int) -> Int {
return number/100; //4131/100 = 41
}
To find the first two digit you might need to change the logic on the basis of face value of number. Below method is generalise method to find each digit of a number.
func printDigits(number : Int) {
var num = number
while num > 0 {
var digit = num % 10 //get the last digit
println("\(digit)")
num = num / 10 //remove the last digit
}
}

NSDecimalNumber and popping digits off of the end

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.