16

This works

let replaced = String(map(aString.generate()) {
    $0 == " " ? "-" : $0 })

and this doesn't

let replaced = String(map(aString.generate()) {
    $0 == " " ? "" : $0 })

Why?

Pang
  • 9,564
  • 146
  • 81
  • 122
Kate Zz
  • 3,002
  • 5
  • 14
  • 17

12 Answers12

22

For Swift 5:

" spaces here ".replacingOccurrences(of: " ", with: "")

returns:

"spaceshere"
Shaked Sayag
  • 5,712
  • 2
  • 31
  • 38
17

Enumerating a string gives a sequence of characters, so $0 inside the closure has the type Character. This compiles

{ $0 == " " ? "-" : $0 }

because "-" in this context is interpreted as a character literal and therefore of the same type as $0. But

{ $0 == " " ? "" : $0 }

does not compile because "" is not a character literal (and in the conditional expression a ? b : c the operands b and c must have the same type).

You can fix that by converting $0 to a string:

{ $0 == " " ? "" : String($0) }

but now the mapping returns an array of strings instead of an array of characters. So instead of the String() constructor you have to join the results:

let replaced = "".join(map(aString) { $0 == " " ? "" : String($0) })
// Swift 2 / Xcode 7:
let replaced = "".join(aString.characters.map({ $0 == " " ? "" : String($0) }))

(Note that calling generate() explicitly is not needed.)

Of course the same result would also be achieved with

// Before Swift 3.0
let replaced = aString.stringByReplacingOccurrencesOfString(" ", withString: "")

// After Swift 3.0
let replaced = aString.replacingOccurrences(of: " ", with: "")
Peter
  • 29
  • 1
  • 5
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • There are now 12 answers and this is the only answer that actually answers the question being asked, not simply the title. It's a shame the OP never accepted it. – HangarRash May 22 '23 at 00:17
8

If you want to remove white space from string then just pass string with stringByReplacingOccurrencesOfString function like below,

let replacedString = string.replacingOccurrences(of: " ", with: "")

For Text Fields, you can apply directly object of UITextField,

let replacedString = textField.text!.replacingOccurrences(of: " ", with: "")
liudasbar
  • 173
  • 4
  • 11
iAnkit
  • 1,940
  • 19
  • 25
7

This should work as of Swift 2.2:

let replaced = String(aString.characters.filter {$0 != " "})
EFC
  • 1,890
  • 18
  • 39
  • I worked with numbers with spaces, I don't know why, but just this variant removes spaces in decimal numbers, thanks! – Alexander B Mar 09 '21 at 15:53
5

If you want to delete whitespaces before and after a string, which is very useful in user input forms, you can use:

let replaced = aString.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())

You can apply it directly on a textfield as well.

Henk-Martijn
  • 2,024
  • 21
  • 25
4

If you want to remove all whitespaces anywhere in the String I did come up with this solution for Swift 3.0:

let number = "+000 000 000"
let nonWhiteCharacters = number.unicodeScalars.filter {
    false == NSCharacterSet.whitespacesAndNewlines.contains($0)
}.map(Character.init)
let whitespacelessNumber = String(nonWhiteCharacters)

or even better (you will need generic extension on Sequence):

extension Sequence {
    public func reduce<Result>(_ result: (Self) throws -> Result) rethrows -> Result {
        return try result(self)
    }
}

and then you can write:

let whitespacelessNumber = number.unicodeScalars.filter {
    false == NSCharacterSet.whitespacesAndNewlines.contains($0)
}.map(Character.init).reduce { String($0) }

where you can also replace NSCharacterSet.whitespacesAndNewlines for any of other character sets:

NSCharacterSet.controlCharacters
NSCharacterSet.whitespaces
NSCharacterSet.whitespacesAndNewlines
NSCharacterSet.decimalDigits
NSCharacterSet.letters
NSCharacterSet.lowercaseLetters
NSCharacterSet.uppercaseLetters
NSCharacterSet.nonBaseCharacters
NSCharacterSet.alphanumerics
NSCharacterSet.decomposables
NSCharacterSet.illegalCharacters
NSCharacterSet.punctuationCharacters
NSCharacterSet.capitalizedLetters
NSCharacterSet.symbols
NSCharacterSet.newline
5keeve
  • 176
  • 2
  • 7
4

None of the previous answers where Swifty enough for me, so I ended up with this using Swift 5:

let nonWhitespaceString = String(whitespaceString.compactMap({ $0.isWhitespace ? nil : $0 })
juhan_h
  • 3,965
  • 4
  • 29
  • 35
3

You are mapping thus the number of elements should be preserved. In the second case you remove elements. Your example will fail even in case you replace " " with --.

You might prefer using filter:

let replaced = String(filter(aString.generate()) { $0 != " "})
Matteo Piombo
  • 6,688
  • 2
  • 25
  • 25
2

try this one:

let strArray0 = strArray1.map { $0.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()) }

Hope this helps

Daniel
  • 357
  • 2
  • 11
1

In Swift 3.0 DO as

func RemoveWhiteSpace(aString:String) -> String
    {
        let replaced = aString.trimmingCharacters(in: NSCharacterSet.whitespaces)
        return replaced
    }

And use like this

let nonWhiteSpaceStr = self.RemoveWhiteSpace(aString: "I have white Space        ")
0

NOTE: juhan_h's answer on this question is a more succinct version if whitespace is really all you're interested in stripping out. https://stackoverflow.com/a/57425783/5946596

Swift 5.5

All the answers are great for removing spaces but sometimes I want to remove any whitespaces and newLines throwing in _ and - ... who knows.

The following extension on string lets me do that.

extension String {
    func removingCharacters(_ characters:CharacterSet) -> Self {
        Self(self.unicodeScalars.filter {
            !characters.contains($0)
        })
    }
    func removingCharacters(in string:String) -> Self {
        Self(self.unicodeScalars.filter {
            !CharacterSet(charactersIn:string).contains($0)
        })
    }
    
    func replacingCharacters(_ characters:CharacterSet, with newChar:Character) -> Self {
        String(self.compactMap( {
            CharacterSet(charactersIn: "\($0)").isSubset(of: characters)
             ? newChar : $0
        }))
    }
    
    func replacingCharacters(in string:String, with newChar:Character) -> Self {
        String(self.compactMap( {
            CharacterSet(charactersIn: "\($0)").isSubset(of: CharacterSet(charactersIn:string))
             ? newChar : $0
        }))
    }
}

usage:

print("hello \n my name\t is Joe".removingCharacters(.whitespacesAndNewlines))
print("hello \n my name\t is Joe".removingCharacters(in: " \t\n"))

print("ban annan anann ana".replacingCharacters(.whitespacesAndNewlines, with: "_"))
print("ban-annan anann ana".replacingCharacters(in: " -", with: "_"))

Obviously for just spaces the .replacingOccurrences(of: " ", with: "") is better.

I have not done a performance comparison to the

let toArray = aString.components(separatedBy: characterSet)
let backToString = toArray.joined(separator: "+") 

style done in Ramis's extension on this question:

https://stackoverflow.com/a/33120336/5946596

I'd be interested if someone does.

See also replacing emojis: https://stackoverflow.com/a/63416058/5946596

carlynorama
  • 166
  • 7
0

Swift 5 --- Best answer based on performance tests

I took a look at the two most common answers and did some performance tests. Both were similar in time performance when about half the characters were whitespace, but there was always big difference in memory performance.

Note: Take a look at additional performance data at the bottom - if you have a lot of large strings with very few whitespaces in them, the regex version (named removingWhitespacesRegex below) was much, much faster.

// Tested on 1,000 character string with 500 whitespace characters

extension String {

    // Best performance memory-wise
    var removingWhitespacesMap: String {
        String(self.compactMap { $0.isWhitespace ? nil : $0 })
    }

    // Far less efficient memory-wise
    var removingWhitespacesRegex: String {
        replacingOccurrences(of: "\\s", with: "", options: .regularExpression)
    }

}

Performance test details

I ran both methods 100,000 times on a 1,000 character string containing 500 whitespace characters (spaces and new lines). E.g.

func test_String_removingWhitespacesMap_performance() {
    measure(metrics: [XCTClockMetric(), XCTMemoryMetric()]) {
        for _ in 1...100000 {
            let _ = whitespaceString.removingWhitespacesMap
        }
    }
}

Time performance

The removingWhitespacesMap method took about 7.9 seconds to complete compared to removingWhitespacesRegex taking 7.6 seconds. Not surprising that the RegEx optimized method performed a little better with such huge input strings. I don't think this time difference is enough to matter unless you're working with millions of strings.

Memory performance

I looked at the "Memory Peak Physical" measurement since "Memory Physical" often comes back negative and I couldn't find anywhere what that is supposed to mean. The removingWhitespacesMap method used 41,301 kB memory peak physical, while removingWhitespacesRegex used 805,062 kB memory peak physical, about 20x more!

Additional Testing

This was interesting, you may want to take these results into account if you know your string is mostly whitespace or mostly non-whitespace. Specifically, if the string is large and mostly non-whitespace, you might want to use the regex version. It was much faster on a large scale.

1,000 character string with 999 spaces and 1 non-whitespace character at the end:

removingWhitespacesMap 18 seconds, 40,453 kB

removingWhitespacesRegex 10.1 seconds, 1,864,835 kB (!!!)

1,000 character string with 1 space at the end and 999 non-whitespace characters:

removingWhitespacesMap 21.5 seconds, 41,180 kB

removingWhitespacesRegex 0.45 seconds (!!!), 288,550 kB

Trev14
  • 3,626
  • 2
  • 31
  • 40