CharacterSet.decimalDigits not allowing decimal point

I am using this piece of code


func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

let allowedCharacters = CharacterSet.decimalDigits

let characterSet = NSCharacterSet(charactersIn: string)

return allowedCharacters.isSuperset(of: characterSet as CharacterSet)

}


However, no decimal point is registering. What gives?

Accepted Reply

Well, I meant the API represented by the Swift CharacterSet class. So:


let both = CharacterSet.decimalDigits.union (CharacterSet (charactersIn: "."))

Replies

Well, I assume because decimal points are not decimal digits?


Keep in mind:


— These predefined character sets are static sets of characters falling into various Unicode character classes.


— The decimal point character is locale-specific.


If you want to find out if a string is a valid numeric representation, use a NumberFormatter (set to an appropriate locale) to convert the string representation.

Would I be able to add the period as a union of decimalDigits and a new character set?

CharacterSet.decimalDigits.union (CharacterSet (charactersIn: "."))

Hopefully posting this link isnt a problem. but Ive gotten that far, now i have a new problem haha... https://stackoverflow.com/questions/44731355/value-of-tuple-void-aka-has-no-member-issuperset

Don't you get this compilation error?


Constant 'both' inferred to have type 'Void', which may be unexpected


Because: CFCharacterSetUnion doesn't return a result.


Why are you using CoreFoundation when there are perfectly good Swift Foundation APIs that are easier to use??

I've never gone about using an API before. I'm not opposed but wouldn't know how to start

Well, I meant the API represented by the Swift CharacterSet class. So:


let both = CharacterSet.decimalDigits.union (CharacterSet (charactersIn: "."))

I appreciate the code clean up. Bummer is now I receive a exec-bad access error during runtime - when i input (or try) any character. Ill update my SO question to display this.

I'm not seeing the crash with this code:


let allowed = CharacterSet.decimalDigits
let period = CharacterSet(charactersIn: ".")
let both = allowed.union(period)

let characterSet = CharacterSet(charactersIn: "01.2")

print (both.isSuperset(of: characterSet))

Supposedly theres a bug with the code mentioned by another user on SO

I want to swing back to a point that QuinceyMorris made right at the start of this thread:

The decimal point character is locale-specific.

It’s not just the decimal point that’s a concern here, it’s the digits themselves. For example:

let digits = CharacterSet.decimalDigits
let d = UnicodeScalar(0x0661)!  // U+0661 ARABIC-INDIC DIGIT ONE
print(digits.contains(d))       // prints "true"

So, either you want to support internationalisation or you don’t. If you do, you really need to look at

NumberFormatter
because any other approach is fraught with much danger. If you don’t — and there are plenty of contexts where it’s safe to ignore internationalisation — you should eschew
decimalDigits
and just build a digits set from the ASCII 0 through 9.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"