NSNumberFormatter grouping - ios

I would like to format string with numbers to look like this: XX XX XX (e.g. 12 34 56)
I'm using NSNumberFormatter with grouping separator:
let formatter = NSNumberFormatter()
formatter.usesGroupingSeparator = true
formatter.groupingSize = 2
formatter.groupingSeparator = " "
if let number = Int(theText.stringByReplacingOccurrencesOfString(" ", withString: "")) {
let numberToFormat = NSNumber(integer:number)
textField.text = formatter.stringFromNumber(numberToFormat)
}
This will work fine, if you enter number 123456 - it is formatted to 12 34 56
I use this inside shouldChangeCharactersInRange method so it should format number as you type. Grouping separator defines numbers are grouped by groupingSize value from right side, so when you type in 123456 this is how text changes:
1
12
1 23
12 34
1 23 45
12 34 45
and I would like to format it as following:
1
12
12 3
12 34
12 34 5
12 34 56
Is it possible to define from which side grouping separator groups numbers?

Not sure if you have to covert to Int, how about add a "0" at the end? Then remove the last "0".
let formatter = NSNumberFormatter()
formatter.usesGroupingSeparator = true
formatter.groupingSize = 2
formatter.groupingSeparator = " "
var str = "12345"
if str.characters.count % 2 != 0 {
str += "0"
}
if let number = Int(str.stringByReplacingOccurrencesOfString(" ", withString: "")) {
let numberToFormat = NSNumber(integer:number)
formatter.stringFromNumber(numberToFormat)
}
Another solution:
let string = "12345"
var results = [String]()
for index in 0 ..< string.characters.count-1 {
if index % 2 == 0 {
let range = NSRange(location: index, length: 2)
results.append((string as NSString).substringWithRange(range))
}
}
if string.characters.count % 2 != 0 {
let last = (string as NSString).substringFromIndex(string.characters.count-1)
results.append(last)
}

Swit 4
You have to use the delegate of UITextField : func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String)
this works fine :
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == YourTextField {
if (textField.text?.count)! < 8 {
let formatter = NumberFormatter()
formatter.usesGroupingSeparator = true
formatter.locale = NSLocale(localeIdentifier: "en_GB") as Locale?
formatter.groupingSize = 2
formatter.groupingSeparator = "-" // if you want the format XX-XX-XX
// Uses the grouping separator corresponding
if let groupingSeparator = formatter.groupingSeparator {
if string == groupingSeparator {
return true
}
if let textWithoutGroupingSeparator = textField.text?.replacingOccurrences(of: groupingSeparator, with: "") {
var totalTextWithoutGroupingSeparators = textWithoutGroupingSeparator + string
if string == "" { // pressed Backspace key
totalTextWithoutGroupingSeparators.characters.removeLast()
}
if let numberWithoutGroupingSeparator = formatter.number(from: totalTextWithoutGroupingSeparators),
let formattedText = formatter.string(from: numberWithoutGroupingSeparator) {
print(numberWithoutGroupingSeparator)
numberWithoutGroupingSeparators = String(format: "%#", numberWithoutGroupingSeparator)
textField.text = formattedText
return false
}
}
}
return true
}
}
return true
}

Related

UITextField Currency Format Left to Right

I want to format my UITextField with having a $ on the left when I enter an amount.
So far what my code does is when I enter let says $5.65 this is how it's entered: $0.05 -> $0.56 -> $5.65
I want it so that it's not right to left but left to right so something like this: $5 -> $5. -> $5.6 -> $5.65
But I want to restrict it to only two decimals place, the dollar sign is on the left, and you can not type any other characters (e.g: !,#,#,$,%,^, A-Z')
This is what I have currently:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text: NSString = (textField.text ?? "") as NSString
let finalString = text.replacingCharacters(in: range, with: string)
// 'currency' is a String extension that doews all the number styling
amuTextField.text = finalString.currency
// returning 'false' so that textfield will not be updated here, instead from styling extension
return false
}
func currencyInputFormatting() -> String {
var number: NSNumber!
let formatter = NumberFormatter()
formatter.numberStyle = .currencyAccounting
formatter.currencySymbol = "$"
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
var amountWithPrefix = self
// remove from String: "$", ".", ","
let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count), withTemplate: "")
let double = (amountWithPrefix as NSString).doubleValue
number = NSNumber(value: (double / 100))
return formatter.string(from: number)!
}
You could use this to limit the decimal places after the .:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let oldText = textField.text, let r = Range(range, in: oldText) else {
return true
}
let newText = oldText.replacingCharacters(in: r, with: string)
let isNumeric = newText.isEmpty || (Double(newText) != nil)
let numberOfDots = newText.components(separatedBy: ".").count - 1
let numberOfDecimalDigits: Int
if let dotIndex = newText.firstIndex(of: ".") {
numberOfDecimalDigits = newText.distance(from: dotIndex, to: newText.endIndex) - 1
} else {
numberOfDecimalDigits = 0
}
return isNumeric && numberOfDots <= 1 && numberOfDecimalDigits <= 2
}

Dynamically format a number to have commas in a UITextField

How to format the price textfield text as a currency format like 234,345,567 and also I need to restrict the decimal points to not more than 2 and also to append $ symbol when user starts typing.
for example : $234,345,678.25
like this I want to add comma between 3numbers when they type the amount in textfield
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if ((string == "0" || string == "") && (txtFldPostalCode.text! as NSString).range(of: ".").location < range.location) {
return true
}
let cs = NSCharacterSet(charactersIn: "0123456789.").inverted
let filtered = string.components(separatedBy: cs)
let component = filtered.joined(separator: "")
let isNumeric = string == component
if isNumeric {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 8
let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
let numberWithOutCommas = newString.replacingOccurrences(of: ",", with: "")
let number = formatter.number(from: numberWithOutCommas)
if number != nil {
var formattedString = formatter.string(from: number!)
if string == "." && range.location == textField.text?.length {
formattedString = formattedString?.appending(".")
}
textField.text = formattedString
} else {
textField.text = nil
}
}
return false
}
For Swift 3. Input currency format on a text field (from right to left)
#IBOutlet weak var textfield: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textfield.addTarget(self, action: #selector(myTextFieldDidChange), for: .editingChanged)
// Do any additional setup after loading the view.
}
#objc func myTextFieldDidChange(_ textField: UITextField) {
if let amountString = textField.text?.currencyInputFormatting() {
textField.text = amountString
}
}
}
extension String {
// formatting text for currency textField
func currencyInputFormatting() -> String {
var number: NSNumber!
let formatter = NumberFormatter()
formatter.numberStyle = .currencyAccounting
formatter.currencySymbol = "$"
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
var amountWithPrefix = self
let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count), withTemplate: "")
let double = (amountWithPrefix as NSString).doubleValue
number = NSNumber(value: (double / 100))
guard number != 0 as NSNumber else {
return ""
}
return formatter.string(from: number)!
}
Hope this is helpful...

how to add 2 textfields togethers as int (swift3)

I am trying to convert 2 textfields to ints and then add them together. I would also like to print the sum in the log.
let jake = t3.text! + t4.text!
Convert text into Int in Swift and an addition like we can do...
//set before this condition Validation for Text field
let sum = (Int(textFirst.text ?? "0")! + Int(textSecond.text ?? "0"))!
print(sum) //Output here
//MARK: - Text Field Delegate Method for Input validation
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
let allowedCharacters = CharacterSet.decimalDigits
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
}
let t3Value: Int? = Int(t3.text!)
let t4Value: Int? = Int(t4.text!)
let final = t3Value! + t4Value!
print("Sum \(final)")
Hope this helps!
Try this:
if let val1 = Int(t3.text!), let val2 = Int(t4.text!)
{
let sum = val1 + val2
print(sum)
}

Percentage mask for textfield in Swift

Ive been trying to achieve a percentage mask for a textfield that starts with the value 0.00%. If a user taps '1' it will become 0.01%. If they then tap 0 it becomes 0.10% and so on.
I've achieved this already with currency. And I've come very close using percentage but not managed to create exactly what I'm after.
So, field is originally set to 0.00%. I'd like to display the percentage symbol, I'd like the max number to be 100.00%, I'd like the max decimal places to be 2, and like the field to be updated when the user types and I'd like them to be able to press backspace to delete the last number entered. Oh and also when it reaches the maximum of 100.00, pressing another number does not reset the value, or do anything screwy.
Here is the code I've tried. I've also tried MANY variations:
func textFieldDidChanged(textField: UITextField) {
numberFormatter.numberStyle = .PercentStyle
numberFormatter.maximumFractionDigits = 2
numberFormatter.minimumFractionDigits = 2
numberFormatter.maximum = 100
let text = textField.text!.stringByReplacingOccurrencesOfString(numberFormatter.percentSymbol, withString: "").stringByReplacingOccurrencesOfString(numberFormatter.groupingSeparator, withString: "").stringByReplacingOccurrencesOfString(numberFormatter.decimalSeparator, withString: "")
textField.text = numberFormatter.stringFromNumber((text as NSString).doubleValue / 100.0)
}
I've looked all over, and spent way too long on this. Please help.
This is what I came up with (and for my application, its about as much effort I want to give). Two cases need to be handled: 1) inputting and 2) deleting. Handling the input was the easier portion (modified from a previous post). Handling the delete was trickier to realize. Basically when backspace is detected, move right one decimal place.
Handles input:
mInputRate.addTarget(self, action: #selector(rateTextFieldChanged), for: .editingChanged)
...
#objc func rateTextFieldChanged (_ textField : UITextField){
if let amountString = textField.text?.rateInputFormatting() {
textField.text = amountString
calculate()
}
}
and
extension String {
// formatting text for currency textField
func rateInputFormatting() -> String {
var number: NSNumber!
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 3
formatter.minimumFractionDigits = 3
formatter.maximum = 100
formatter.minimum = 0
var amountWithPrefix = self
// remove from String: "$", ".", ","
let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count), withTemplate: "")
let double = (amountWithPrefix as NSString).doubleValue
number = NSNumber(value: (double / 1000))
// if first number is 0 or all numbers were deleted
guard number != 0 as NSNumber else {
return ""
}
return "\(formatter.string(from: number)!)%"
}
}
This handles delete (backspace):
extension CalculatorVC : UITextFieldDelegate{
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
//delete the second to last character
let text = textField.text!
let textDouble = text.replacingOccurrences(of: "%", with: "")
let doubleAdjusted = Double(textDouble)! / 10.0
//pad to three decimal places
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 3
formatter.minimumFractionDigits = 3
formatter.roundingMode = .down
let num = NSNumber(value: doubleAdjusted)
let newText = formatter.string(from: num)!
textField.text = "\(newText)%"
}
return true
}
}

How to Format Textfiled.text in Turkish Phone Format?

I've a textfield which only takes phone number and I'm trying to format it into Turkish format number which looks like this (555) 555 5555. How can I make that in Swift?
You can do something like this on EiditingChange method, this will change first three entries to this () format while user inputs text, you can follow same approach to remove format if user is deleting entries
#IBAction func onEditingChanged(sender: UITextField!)
{
var string = sender.text as NSString
if string.length > 3
{
let range = string.rangeOfString("(")
if range.location == NSNotFound
{
var firstPart = string.substringToIndex(3)
var secondPart = string.substringFromIndex(3)
var string = "(\(firstPart))\(secondPart)"
sender.text = string
}
}
}
Well if we take the assumption that all Turkish numbers are 10 digits long, we can do it as follows.
First lets define a helper function to get the substrings:
func sub(str: String, start: Int, end: Int) -> String {
return str.substringWithRange(Range<String.Index>(start: advance(str.startIndex, start), end: advance(str.startIndex, end)))
}
Now we just apply the function to get the sections of the number:
// Lets say this is the number we get from the textfield
let number = "1234567890"
let start = sub(number, 0, 3) // "123"
let mid = sub(number, 3, 6) // "456"
let end = sub(number, 6, 10) // "7890"
And then we format this into a single string as desired.
let formatNumber = "(\(start)) \(mid) \(end)" // "(123) 456 7890"
Note that this would only work for numbers that have 10 digits (I doubt that all Turkish numbers are). You would need to modify this to format for numbers of different lengths, by specifying different substrings of the start mid and end above.
If you wanted to limit the user to only using 10 digit numbers, you should perform validation on textfield.
var shouldAttemptFormat: Bool = true
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField == self.phoneNumberTextField{
let resultString: String = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString:string)
let oldString: String = self.phoneNumberTextField.text
let oldCount = count(oldString)
let newCount = count(resultString)
shouldAttemptFormat = newCount > oldCount
return true//newCount < 15
}else{
return true
}
// otherwise we should just let them continue
}
// MARK: - phone number formatting
func formatPhoneNumber() {
// this value is determined when textField shouldChangeCharactersInRange is called on a phone
// number cell - if a user is deleting characters we don't want to try to format it, otherwise
// using the current logic below certain deletions will have no effect
if !shouldAttemptFormat {
return
}
// here we are leveraging some of the objective-c NSString functions to help parse and modify
// the phone number... first we strip anything that's not a number from the textfield, and then
// depending on the current value we append formatting characters to make it pretty
let currentValue: NSString = self.phoneNumberTextField.text
let strippedValue: NSString = currentValue.stringByReplacingOccurrencesOfString("[^0-9]", withString: "", options: .RegularExpressionSearch, range: NSMakeRange(0, currentValue.length))
var formattedString: NSString = ""
if strippedValue.length == 0 {
formattedString = "";
}
else if strippedValue.length < 3 {
formattedString = "(" + (strippedValue as String)
}
else if strippedValue.length == 3 {
formattedString = "(" + (strippedValue as String) + ") "
}
else if strippedValue.length < 6 {
formattedString = "(" + strippedValue.substringToIndex(3) + ") " + strippedValue.substringFromIndex(3)
}
else if strippedValue.length == 6 {
formattedString = "(" + strippedValue.substringToIndex(3) + ") " + strippedValue.substringFromIndex(3) + "-"
}
else if strippedValue.length <= 10 {
formattedString = "(" + strippedValue.substringToIndex(3) + ") " + strippedValue.substringWithRange(NSMakeRange(3, 3)) + "-" + strippedValue.substringFromIndex(6)
}
else if strippedValue.length >= 11 {
formattedString = "(" + strippedValue.substringToIndex(3) + ") " + strippedValue.substringWithRange(NSMakeRange(3, 3)) + "-" + strippedValue.substringWithRange(NSMakeRange(6, 4))
}
self.phoneNumberTextField.text = formattedString as String
}
I use this code as it looks above, It works. When user type any character, formatPhoneNumber function works, for each char.
self.phoneNumberTextField.addTarget(self, action: "formatPhoneNumber", forControlEvents: .EditingChanged)
You must to add this line in viewDidLoad.
Hopefully, it will work for you

Resources