How to remove multiple spaces in Strings with Swift 2
Asked Answered
N

8

31

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!

Napery answered 10/10, 2015 at 20:31 Comment(0)
V
57

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!"
Vidavidal answered 10/10, 2015 at 20:41 Comment(2)
be careful, if you want to make it work with whitespacesAndNewlines you need to manage new lines as new lines and not " " when you join. ** func condenseWhitespace() -> String { let components = self.components(separatedBy: .whitespaces) let tmpstr = components.filter { !$0.isEmpty }.joined(separator: " ") let components2 = tmpstr.components(separatedBy: .newlines) return components2.filter { !$0.isEmpty }.joined(separator: "\n") }**Rightism
The extension works great in Swift 5. Lifesaving code! Thank you :)Carter
P
32

Splitting the string to an array and then joining again is not memory-efficient. It takes a lot of memory. The best way in this case is to scan the given string and perform operations on it using regular expressions. The solution is given below:

Swift 4.x

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

Usage:

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

Output:

"Hello world! I am here!"

You can do more according to your own requirements, but my point here is to use regular expressions rather than creating arrays which would consume lots of memory.

Pretrice answered 5/12, 2018 at 8:11 Comment(2)
Thank you! This is better than creating unnecessary arrays.Morrill
@JeanNicolas For That, you can use .trimmingCharacters(in: .whitespacesAndNewlines) function by adding it to your extension. The Above solution is reducing more than 1 spaces or newlines to 1 space. I will really appreciate if you can make this functionality more responsible to trim the sting also. Thanks :-)Pretrice
P
13

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"

Paryavi answered 11/2, 2020 at 12:0 Comment(0)
D
8

SWIFT 3: Cleaner version

extension String {
    var condensedWhitespace: String {
        let components = self.components(separatedBy: .whitespacesAndNewlines)
        return components.filter { !$0.isEmpty }.joined(separator: " ")
    }
}
Denude answered 11/3, 2017 at 8:23 Comment(2)
What the advantage of using var over func?Jacoby
I don't think it's making any difference. Just saving you ()Denude
E
1

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?

Experience answered 4/6, 2019 at 6:2 Comment(0)
C
1

Code below work for me. I needed to remove EXTRA spaces from string.

var example = "    Hello       world   "

func removeSpacers(from word: String) -> String {
var finalResult = ""
var spacesCount = 0

let trimmed = word.trimmingCharacters(in: .whitespaces)
let components = trimmed.components(separatedBy: " ")

// if we have not any spaces we returning trimmed string
guard components.contains(where: { $0 == "" }) else { return trimmed }
components.forEach {
    // because .components returning ""(empty string)
    if $0 == "" {
        spacesCount += 1
    } else {
        // if another element not space, we could add space(the space between words)
        if spacesCount != 0 {
            spacesCount = 0
            finalResult.append(" ")
        }
    }
    // so if we have no spaces we could add word no result string
    if spacesCount == 0 {
        finalResult.append($0)
    }
}
return finalResult

}

I make a couple of tests, its work.

 func testRemoveSpaceFromStringWithSpacesOnCenter() {
    // given
    let string = "Hello     world"

    // when
    let result = pfromatter.removeSpaces(from: string)

    // then
    let expected = "Hello world"
    XCTAssertEqual(expected, result)
}

func testRemoveSpaceFromStringWithSpacesOnSide() {
    // given
    let string = " Hello world "

    // when
    let result = pfromatter.removeSpaces(from: string)

    // then
    let expected = "Hello world"
    XCTAssertEqual(expected, result)
}
Caroncarotene answered 14/10, 2023 at 20:34 Comment(0)
C
0
var str = "Hello  World.\nHello!"

if let regex = try? NSRegularExpression(pattern: "\\s+", options:NSRegularExpression.Options.caseInsensitive)
{
    str = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.count), withTemplate: " ")

}
Cathey answered 4/4, 2019 at 7:16 Comment(0)
G
0

If you want to remove duplicate whitespace and any leading/trailing whitespace in one go, you can use the below solution:

extension String {
    func trimmingExtraWhitespace() -> String {
        return self.replacingOccurrences(of: "(?<=\\s)\\s+|\\s+(?=$)|(?<=^)\\s+", 
                                         with: "", 
                                         options: .regularExpression)
    }
}

What it does:

  • (?<=\\s)\\s+ matches all whitespace preceded by a space
  • \\s+(?=$) matches all whitespace at the end of a string
  • (?<=^)\\s+ matches all whitespace at the beginning of a string

Remarks:

  • \s in regex includes spaces, tabs and line breaks, so you don't need to explicitly specify \n.
  • You need to escape \s in Swift, thus the double backward slash \\

Example:

var originalString = "  Hello   world  "
var processedString = originalString.trimmingExtraWhitespace()
print("Original: \(originalString)")
print("Processed: \(processedString)")

Output:

Original:   Hello   world  
Processed: Hello world
Gaia answered 30/10, 2023 at 5:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.