Tommy Wei
Tommy Wei

Reputation: 273

Swift NSAttributedString Trim

I want to get ride of the white spaces in front and at the end of my NSAttributedString(Trimming it). I can't simply convert it to string and do trimming because there are images(attachments) in it. How can i do it?

Upvotes: 27

Views: 10000

Answers (7)

Johannes Fahrenkrug
Johannes Fahrenkrug

Reputation: 44826

It turns out that Unicode strings are hard hahaha! The other solutions posted here are a great starting point, but they crashed for me when using non-latin strings. Whenever using indexes or ranges in Swift Strings, we need to use String.Index instead of plain Int. Creating an NSRange from a Range<String.Index> has to be done with NSRange(swiftRange, in: String).

That being said, this code builds on the other answers, but makes it unicode-proof:

public extension NSMutableAttributedString {

    /// Trims new lines and whitespaces off the beginning and the end of attributed strings
    func trimmedAttributedString() -> NSAttributedString {
        let invertedSet = CharacterSet.whitespacesAndNewlines.inverted
        let startRange = string.rangeOfCharacter(from: invertedSet)
        let endRange = string.rangeOfCharacter(from: invertedSet, options: .backwards)
        guard let startLocation = startRange?.lowerBound, let endLocation = endRange?.lowerBound else {
            return NSAttributedString(string: string)
        }

        let trimmedRange = startLocation...endLocation
        return attributedSubstring(from: NSRange(trimmedRange, in: string))
    }
}

Upvotes: 5

Bhautik Ziniya
Bhautik Ziniya

Reputation: 1564

Create extension of NSAttributedString as below.

extension NSAttributedString {
     public func attributedStringByTrimmingCharacterSet(charSet: CharacterSet) -> NSAttributedString {
         let modifiedString = NSMutableAttributedString(attributedString: self)
        modifiedString.trimCharactersInSet(charSet: charSet)
         return NSAttributedString(attributedString: modifiedString)
     }
}

extension NSMutableAttributedString {
     public func trimCharactersInSet(charSet: CharacterSet) {
        var range = (string as NSString).rangeOfCharacter(from: charSet as CharacterSet)

         // Trim leading characters from character set.
         while range.length != 0 && range.location == 0 {
            replaceCharacters(in: range, with: "")
            range = (string as NSString).rangeOfCharacter(from: charSet)
         }

         // Trim trailing characters from character set.
        range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
         while range.length != 0 && NSMaxRange(range) == length {
            replaceCharacters(in: range, with: "")
            range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards)
         }
     }
}

and use in viewController where you want to use. like this

let attstring = NSAttributedString(string: "this is test message. Please wait.                   ")
let result = attstring.attributedStringByTrimmingCharacterSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())

Upvotes: 31

kamalraj venkatesan
kamalraj venkatesan

Reputation: 425

This works even with emoji in the text

extension NSAttributedString {

    /** Will Trim space and new line from start and end of the text */
    public func trimWhiteSpace() -> NSAttributedString {
        let invertedSet = CharacterSet.whitespacesAndNewlines.inverted
        let startRange = string.utf16.description.rangeOfCharacter(from: invertedSet)
        let endRange = string.utf16.description.rangeOfCharacter(from: invertedSet, options: .backwards)
        guard let startLocation = startRange?.upperBound, let endLocation = endRange?.lowerBound else {
            return NSAttributedString(string: string)
        }

        let location = string.utf16.distance(from: string.startIndex, to: startLocation) - 1
        let length = string.utf16.distance(from: startLocation, to: endLocation) + 2
        let range = NSRange(location: location, length: length)
        return attributedSubstring(from: range)
    }

}

USAGE

let attributeString = NSAttributedString(string: "\n\n\n     Hi πŸ‘‹ πŸ‘©β€πŸ‘©β€πŸ‘§πŸ‘©β€πŸ‘©β€πŸ‘¦β€πŸ‘¦πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦πŸ‘©β€πŸ‘¦πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦β€πŸ‘¦πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘¦πŸ‘©β€πŸ‘§β€πŸ‘¦πŸ‘©β€πŸ‘¦β€πŸ‘¦πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¦ buddy.              ")
let result = attributeString.trimWhiteSpace().string // Hi πŸ‘‹ πŸ‘©β€πŸ‘©β€πŸ‘§πŸ‘©β€πŸ‘©β€πŸ‘¦β€πŸ‘¦πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦πŸ‘©β€πŸ‘¦πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦β€πŸ‘¦πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘¦πŸ‘©β€πŸ‘§β€πŸ‘¦πŸ‘©β€πŸ‘¦β€πŸ‘¦πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¦ buddy.

Upvotes: 13

Suhit Patil
Suhit Patil

Reputation: 12023

Swift 4 and above

extension NSMutableAttributedString {

    func trimmedAttributedString() -> NSAttributedString {
        let invertedSet = CharacterSet.whitespacesAndNewlines.inverted
        let startRange = string.rangeOfCharacter(from: invertedSet)
        let endRange = string.rangeOfCharacter(from: invertedSet, options: .backwards)
        guard let startLocation = startRange?.upperBound, let endLocation = endRange?.lowerBound else {
            return NSAttributedString(string: string)
        }
        let location = string.distance(from: string.startIndex, to: startLocation) - 1
        let length = string.distance(from: startLocation, to: endLocation) + 2
        let range = NSRange(location: location, length: length)
        return attributedSubstring(from: range)
    }
}

use:

let string = "This is string with some space in the end.     "
let attributedText = NSMutableAttributedString(string: string).trimmedAttributedString()

Upvotes: 3

Swift 3.2 Version:

extension NSAttributedString {
    public func trimmingCharacters(in characterSet: CharacterSet) -> NSAttributedString {
        let modifiedString = NSMutableAttributedString(attributedString: self)
        modifiedString.trimCharacters(in: characterSet)
        return NSAttributedString(attributedString: modifiedString)
    }
}

extension NSMutableAttributedString {
    public func trimCharacters(in characterSet: CharacterSet) {
        var range = (string as NSString).rangeOfCharacter(from: characterSet)

        // Trim leading characters from character set.
        while range.length != 0 && range.location == 0 {
            replaceCharacters(in: range, with: "")
            range = (string as NSString).rangeOfCharacter(from: characterSet)
        }

        // Trim trailing characters from character set.
        range = (string as NSString).rangeOfCharacter(from: characterSet, options: .backwards)
        while range.length != 0 && NSMaxRange(range) == length {
            replaceCharacters(in: range, with: "")
            range = (string as NSString).rangeOfCharacter(from: characterSet, options: .backwards)
        }
    }
}

Upvotes: 0

gebirgsb&#228;rbel
gebirgsb&#228;rbel

Reputation: 2397

I made a swift 3 implementation, just in case anyone is interested:

/**
 Trim an attributed string. Can for example be used to remove all leading and trailing spaces and line breaks.
 */
public func attributedStringByTrimmingCharactersInSet(set: CharacterSet) -> NSAttributedString {
    let invertedSet = set.inverted
    let rangeFromStart = string.rangeOfCharacter(from: invertedSet)
    let rangeFromEnd = string.rangeOfCharacter(from: invertedSet, options: .backwards)
    if let startLocation = rangeFromStart?.upperBound, let endLocation = rangeFromEnd?.lowerBound {
        let location = string.distance(from: string.startIndex, to: startLocation) - 1
        let length = string.distance(from: startLocation, to: endLocation) + 2
        let newRange = NSRange(location: location, length: length)
        return self.attributedSubstring(from: newRange)
    } else {
        return NSAttributedString()
    }
}

Upvotes: 2

macpandit
macpandit

Reputation: 833

Following code will work for your requirement.

var attString: NSAttributedString = NSAttributedString(string: " this is att string")

let trimmedString = attString.string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())

Upvotes: -4

Related Questions