How to remove multiple spaces in Strings with Swift 2

12,285

Solution 1

In Swift 2, join has become joinWithSeparator and you call it on the array.

In filter, isEmpty should be called on the current iteration item $0.

To replace whitespaces and newline characters with unique space characters as in your question:

extension String {
    func condenseWhitespace() -> String {
        let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
        return components.filter { !$0.isEmpty }.joinWithSeparator(" ")
    }
}

let result = "Hello  World.\nHello!".condenseWhitespace()  // "Hello World. Hello!"

Because your function does not take any parameter you could make it a property instead:

extension String {
    var condensedWhitespace: String {
        let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
        return components.filter { !$0.isEmpty }.joinWithSeparator(" ")
    }
}

let result = "Hello  World.\nHello!".condensedWhitespace  // "Hello World. Hello!"

In Swift 3 there's even more changes.

Function:

extension String {
    func condenseWhitespace() -> String {
        let components = self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
        return components.filter { !$0.isEmpty }.joined(separator: " ")
    }
}

let result = "Hello  World.\nHello!".condenseWhitespace()

Property:

extension String {
    var condensedWhitespace: String {
        let components = self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
        return components.filter { !$0.isEmpty }.joined(separator: " ")
    }
}

let result = "Hello  World.\nHello!".condensedWhitespace

In Swift 4.2 NSCharacterSet is now CharacterSet, and you can omit and use dot syntax:

extension String {
    func condenseWhitespace() -> String {
        let components = self.components(separatedBy: .whitespacesAndNewlines)
        return components.filter { !$0.isEmpty }.joined(separator: " ")
    }
}

let result = "Hello  World.\nHello!".condenseWhitespace()  // "Hello World. Hello!"

Solution 2

Split string to array and then join again in not memory efficient. Its Takes lot of memory. The best way in this case is to scan the given string and perform operations on that. Regular Expression is the advance way to scan a text. For the above conclusion the the solution is given below:

Swift 4.x

extension String {

    func removeExtraSpaces() -> String {
        return self.replacingOccurrences(of: "[\\s\n]+", with: " ", options: .regularExpression, range: nil)
    }

}

Usages

let startingString = "hello   world! \n\n I am   here!"
let processedString = startingString.removeExtraSpaces()
print(processedString)

Output:

processedString => "hello world! I am here!"

You can Do more according to your own requirements but thing I am pointing out here is to use regular expressions with string rather then create arrays which will consume lot of memory.

Solution 3

SWIFT 3: Cleaner version

extension String {
    var condensedWhitespace: String {
        let components = self.components(separatedBy: .whitespacesAndNewlines)
        return components.filter { !$0.isEmpty }.joined(separator: " ")
    }
}

Solution 4

Cleanest version. Documented, memory efficient, extremely easy to use.

extension String {

    /// Returns a condensed string, with no extra whitespaces and no new lines.
    var condensed: String {
        return replacingOccurrences(of: "[\\s\n]+", with: " ", options: .regularExpression, range: nil)
    }

    /// Returns a condensed string, with no whitespaces at all and no new lines.
    var extraCondensed: String {
        return replacingOccurrences(of: "[\\s\n]+", with: "", options: .regularExpression, range: nil)
    }

}

Usage:

let a = " Hello\n  I am  a string  ".condensed
let b = " Hello\n  I am  a string  ".extraCondensed

Output:

a: "Hello I am a string"

b: "HelloIamastring"

Solution 5

Here is mine: How it's actually worked.

extension String {

    func removeExtraSpaces() -> String {
        var data  = ""
        var numberOfSpace = 0
        let items = self.getComponents(separatedBy: " ")
        for item in items{
            if item == " "{
                numberOfSpace = numberOfSpace + 1
            }else{
                numberOfSpace = 0
            }
            if numberOfSpace == 1 || numberOfSpace == 0 {
                data =  data + item
                //data.append(item)
            }
        }
        return data
    }
} 

Usages

 var message = "What  is the    purpose   of life?"
 message = message.removeExtraSpaces()
 print(message)

Output:

What is the purpose of life?

Share:
12,285
headkit
Author by

headkit

pretend to be stupid and become wiser

Updated on June 18, 2022

Comments

  • headkit
    headkit about 2 years

    Until Swift 2 I used this extension to remove multiple whitespaces:

    func condenseWhitespace() -> String {
            let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter({!Swift.isEmpty($0)})
            return " ".join(components)
    }
    

    but with Swift 2 now I get the error

    Cannot invoke 'isEmpty' with an argument list of type '(String)'

    How could I now remove multiple spaces with Swift 2? Thnx!