Filter non-digits from string
SwiftStringNumbersSwift Problem Overview
Using only swift code I cant figure out how to take "(555) 555-5555" and return only the numeric values and get "5555555555". I need to remove all the parentheses, white spaces, and the dash. The only examples I can find are in objective-C and they seem to all use the .trim() method. It appears as though swift doesn't have this method but it does have the .stringByTrimmingCharacters method, but that only seems to trim the white spaces before and after the data.
Swift Solutions
Solution 1 - Swift
Swift 3 & 4
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted)
.joined()
}
}
Swift 5
You should be able to omit return
Also: Read the comment from @onmyway133 for a word of caution
Solution 2 - Swift
Split the string by non-digit characters to an array of digits and the join them back to a string:
Swift 1:
let stringArray = origString.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = NSArray(array: stringArray).componentsJoinedByString("")
Swift 2:
let stringArray = origString.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
Swift 3 & 4:
let newString = origString
.components(separatedBy:CharacterSet.decimalDigits.inverted)
.joined()
Solution 3 - Swift
I like regular expressions:
var s = "(555) 555-5555"
s = s.stringByReplacingOccurrencesOfString(
"\\D", withString: "", options: .RegularExpressionSearch,
range: s.startIndex..<s.endIndex)
Solution 4 - Swift
In Swift 4 the solution is more nice:
import Foundation
let sourceText = "+5 (555) 555-5555"
let allowedCharset = CharacterSet
.decimalDigits
.union(CharacterSet(charactersIn: "+"))
let filteredText = String(sourceText.unicodeScalars.filter(allowedCharset.contains))
print(filteredText) // +55555555555
Solution 5 - Swift
Here is @Tapani's Swift 2.0 answer as a handy String extension, (length property is not part of solution but I left it in example because it is also handy):
import Foundation
extension String {
var length : Int {
return self.characters.count
}
func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
return newString
}
}
Usage:
let phone = "(123)-123 - 1234"
print(phone.digitsOnly())
Solution 6 - Swift
I had a similar issue but I needed to retain the decimal points. I tweaked the top answer to this:
extension String {
/// Returns a string with all non-numeric characters removed
public var numericString: String {
let characterSet = CharacterSet(charactersIn: "0123456789.").inverted
return components(separatedBy: characterSet)
.joined()
}
}
Solution 7 - Swift
Details
- Xcode Version 10.2.1 (10E1001), Swift 5
Solution
import Foundation
extension String {
private func filterCharacters(unicodeScalarsFilter closure: (UnicodeScalar) -> Bool) -> String {
return String(String.UnicodeScalarView(unicodeScalars.filter { closure($0) }))
}
private func filterCharacters(definedIn charSets: [CharacterSet], unicodeScalarsFilter: (CharacterSet, UnicodeScalar) -> Bool) -> String {
if charSets.isEmpty { return self }
let charSet = charSets.reduce(CharacterSet()) { return $0.union($1) }
return filterCharacters { unicodeScalarsFilter(charSet, $0) }
}
func removeCharacters(charSets: [CharacterSet]) -> String { return filterCharacters(definedIn: charSets) { !$0.contains($1) } }
func removeCharacters(charSet: CharacterSet) -> String { return removeCharacters(charSets: [charSet]) }
func onlyCharacters(charSets: [CharacterSet]) -> String { return filterCharacters(definedIn: charSets) { $0.contains($1) } }
func onlyCharacters(charSet: CharacterSet) -> String { return onlyCharacters(charSets: [charSet]) }
}
Usage
let string = "23f45gdor#@%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E"
print("original string: \(string)")
print("only .decimalDigits: \(string.onlyCharacters(charSet: .decimalDigits))")
print("only [.lowercaseLetters, .symbols]: \(string.onlyCharacters(charSets: [.lowercaseLetters, .symbols]))")
print("remove .letters: \(string.removeCharacters(charSet: .letters))")
print("remove [.decimalDigits, .lowercaseLetters]: \(string.removeCharacters(charSets: [.decimalDigits, .lowercaseLetters]))")
Result
original string: 23f45gdor#@%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E
only .decimalDigits: 2345425241309499238304
only [.lowercaseLetters, .symbols]: fgdorivwer+wiuruwu$q+dgnkvljb`keflnwdlqsa`
remove .letters: 2345#@%#425 24 1+ 30949*()92_)$#)_ 38304+{ `; `,.
remove [.decimalDigits, .lowercaseLetters]: #@%# +DWEJ *()ER_)$I#Q)_ U+RFJO{ `; `WKFSA,.E
(Optional) String extension
extension String {
var onlyDigits: String { return onlyCharacters(charSets: [.decimalDigits]) }
var onlyLetters: String { return onlyCharacters(charSets: [.letters]) }
}
(Optional) String extension usage
let string = "23f45gdor#@%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E"
print("original string: \(string)")
print(".onlyDigits: \(string.onlyDigits)")
print(".onlyLetters: \(string.onlyLetters)")
(Optional) String extension usage result
original string: 23f45gdor#@%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E
.onlyDigits: 2345425241309499238304
.onlyLetters: fgdorivwerDWEJwiuruwuERIQUqRFJOdgnkvljbkeflnwdlqsaWKFSAE
Solution 8 - Swift
Try this:
let string = "(555) 555-5555"
let digitString = string.filter { ("0"..."9").contains($0) }
print(digitString) // 5555555555
Putting in extension:
extension String
{
var digitString: String { filter { ("0"..."9").contains($0) } }
}
print("(555) 555-5555".digitString) // 5555555555
Solution 9 - Swift
You'll want to use NSCharacterSet:
Check out this NSHipster link for Swift and Obj-C implementations: http://nshipster.com/nscharacterset/
Similar example:
var string = " Lorem ipsum dolar sit amet. "
let components = string.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).filter({!isEmpty($0)})
string = join(" ", components)
See: punctuationCharacterSet
Description:
Returns a character set containing the characters in the category of Punctuation. Informally, this set is the set of all non-whitespace characters used to separate linguistic units in scripts, such as periods, dashes, parentheses, and so on.
> @Tapani Makes a great suggestion: NSCharacterSet.decimalDigitCharacterSet().invertedSet
Solution 10 - Swift
Here is @Tapani Swift 3.2 solution
let phno = contact.phoneNumbers[0].phoneNumber
let strarr = phno.components(separatedBy: NSCharacterSet.decimalDigits.inverted)
let newString = NSArray(array: strarr).componentsJoined(by: "")
print(newString)
Solution 11 - Swift
Not exactly answered but it looks like a number. I used URLComponents to build the url because it strips out parenthesis and dashes automatically:
var telUrl: URL? {
var component = URLComponents()
component.scheme = "tel"
component.path = "+49 (123) 1234 - 56789"
return component.url
}
then
UIApplication.shared.open(telUrl, options: [:], completionHandler: nil)
calls +49 123 123456789
Solution 12 - Swift
I found the best solution with filter function. Please have a look into it.
let string = "(555) 555-5555"
let onlyDigits = string.filter({ (char) -> Bool in
if Int("\(char)") != nil {
return true
}
else {
return false
}
})