How to filter non numeric digit from String in Swift

Issue #781

This sounds like an easy task, but a quick search on Stackoverflow results in this with highest votes https://stackoverflow.com/questions/29971505/filter-non-digits-from-string

CharacterSet.decimalDigits contains more than just digits

This splits a string by inverted set of decimalDigits and join them back.

1
2
3
4
5
6
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted)
.joined()
}
}

Reading decimalDigits

Informally, this set is the set of all characters used to represent the decimal values 0 through 9. These characters include, for example, the decimal digits of the Indic scripts and Arabic.

So decimalDigits does not only contain digits, but also some scripts in other languages. For normal cases this should not be a problem. As How many decimal digits are there, anyways? there are 610 valid characters in CharacterSet.decimalDigits. So be aware

1
2
3
4
5
6
7
8
9
10
11
12
13
let s = CharacterSet.decimalDigits

// U+0031 DIGIT ONE
s.contains("1") // true as expected

// U+1D7D9 MATHEMATICAL DOUBLE-STRUCK DIGIT ONE
s.contains("𝟙") // true!

// U+0967 DEVANAGARI DIGIT ONE
s.contains("१") // true!

// U+1811 MONGOLIAN DIGIT ONE
s.contains("᠑") // true!

Trimming

Another method is trimmingCharacters. Note that this removes only characters at the start and end of the string.

1
string.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789").inverted)

Just filter

A boring but correct solution is to filter characters anywhere in the string.

1
string.filter("0123456789".contains)

This is more performant than components then join below

1
string.components(separatedBy: CharacterSet(charactersIn: "0123456789").inverted).joined()

Updated at 2021-02-25 08:52:11

Comments