51

The answer in How to strip special characters out of string? is not working.

Here is what I got and it gives me an error

func removeSpecialCharsFromString(str: String) -> String {
    let chars: Set<String> = Set(arrayLiteral: "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-*=(),.:!_")

    return String(str.characters.filter { chars.contains($0) }) //error here at $0
}

The error at $0 says

_Element (aka Character) cannot be converted to expected argument type 'String'.

pkamb
  • 33,281
  • 23
  • 160
  • 191
Harout360
  • 899
  • 1
  • 9
  • 14
  • 2
    The line `let text = str` is just silly. – matt Sep 29 '15 at 19:07
  • In your linked question, the operation is performed on `filter(text)` while you are doing it on `text.characters` which is an array, and String has no initializer using the array of characters and hence your function fails. – Sahil Kapoor Feb 11 '18 at 14:26

6 Answers6

78

Like this:

func removeSpecialCharsFromString(text: String) -> String {
    let okayChars : Set<Character> = 
        Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-*=(),.:!_".characters)
    return String(text.characters.filter {okayChars.contains($0) })
}

And here's how to test:

let s = removeSpecialCharsFromString("père") // "pre"
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • @Kametrixom Agreed; my goal was to fix the OP's syntax, not to solve the actual problem optimally. – matt Sep 29 '15 at 20:13
  • @Kametrixom Changed it to use set instead of array. Lookup in a set should be much more efficient. – matt Sep 29 '15 at 23:14
  • @durul-dalkanat Historical answer. Swift 2! If you want to give a Swift 4 answer, give it; don't change mine. Thanks. – matt Feb 14 '18 at 16:15
50

SWIFT 4:

func removeSpecialCharsFromString(text: String) -> String {
    let okayChars = Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-=().!_")
    return text.filter {okayChars.contains($0) }
}

More cleaner way:

extension String {

    var stripped: String {
        let okayChars = Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-=().!_")
        return self.filter {okayChars.contains($0) }
    }
}

Use this extension like:

let myCleanString = "some.Text@#$".stripped

Output: "some.Text"

Yaroslav Dukal
  • 3,894
  • 29
  • 36
23

I think that a cleaner solution could be this approach:

extension String {
    var alphanumeric: String {
        return self.components(separatedBy: CharacterSet.alphanumerics.inverted).joined().lowercased()
    }
}
Bisca
  • 6,380
  • 2
  • 19
  • 32
10

Try this:

someString.removeAll(where: {$0.isPunctuation})
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Ben Lin
  • 99
  • 1
  • 2
  • 5
    When answering, it's much more helpful to the OP, and any others searching for similar solutions in the future, if you provide some explanation why this is the appropriate solution and how it works. – the Tin Man May 10 '20 at 22:18
8

In Swift 1.2,

let chars = Set("abcde...")

created a set containing all characters from the given string. In Swift 2.0 this has to be done as

let chars = Set("abcde...".characters)

The reason is that a string itself does no longer conform to SequenceType, you have to use the characters view explicitly.

With that change, your method compiles and works as expected:

func removeSpecialCharsFromString(str: String) -> String {
    let chars = Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-*=(),.:!_".characters)
    return String(str.characters.filter { chars.contains($0) })
}

let cleaned = removeSpecialCharsFromString("ab€xy")
print(cleaned) // abxy

Remark: @Kametrixom suggested to create the set only once. So if there is performance issue with the above method you can either move the declaration of the set outside of the function, or make it a local static:

func removeSpecialCharsFromString(str: String) -> String {
    struct Constants {
        static let validChars = Set("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLKMNOPQRSTUVWXYZ1234567890+-*=(),.:!_".characters)
    }
    return String(str.characters.filter { Constants.validChars.contains($0) })
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 2
    I suggest moving the declaration of `chars` outside of the function, as it may be created every time the function is invoked – Kametrixom Sep 29 '15 at 19:19
0

without removing spaces between words

extension String {
    var removeSpecialCharacters: String {
        return self.components(separatedBy: CharacterSet.alphanumerics.inverted).filter({ !$0.isEmpty }).joined(separator: " ")
    }
}