Swift NSAttributedString Trim

26
我想消除我的NSAttributedString开头和结尾处的空格(修剪它)。我不能简单地将其转换为字符串并进行修剪,因为其中包含图像(附件)。我该怎么做?

1
如果您在搜索引擎中查找NSAttributedString和Trim,您会得到一些解决方案,但它们不起作用吗?请参考https://github.com/ovenbits/Alexandria/blob/master/Sources/NSAttributedString%2BExtensions.swift。 - Larme
谢谢Larme,这个Github项目真的很有帮助! - Tommy Wei
7个回答

30
创建下面的NSAttributedString扩展。
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)
         }
     }
}

并在您希望使用的视图控制器中使用。例如:

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

14

这在文本中甚至适用于表情符号

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)
    }

}

使用方法

let attributeString = NSAttributedString(string: "\n\n\n     Hi  ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ buddy.              ")
let result = attributeString.trimWhiteSpace().string // Hi  ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ buddy.

嗨,我想从NSAttributedString中删除最后一个图像附件。你能告诉我怎么做吗? - MALIKK HABIB UR REHMAN
@MALIKKHABIBURREHMAN 你是指将Emoji作为图像吗? - kamalraj venkatesan
不,图像作为NSImageAttachment添加到NSMutableAttributedString中。 - MALIKK HABIB UR REHMAN

4

发现Unicode字符串很难哈哈哈!这里发布的其他解决方案是一个很好的起点,但在使用非拉丁字符时,它们对我产生了崩溃。 无论何时在Swift字符串中使用索引或范围,我们都需要使用String.Index而不是普通的Int。从Range<String.Index>创建NSRange必须使用NSRange(swiftRange, in: String)

话虽如此,该代码基于其他答案进行了构建,但使其支持Unicode:

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))
    }
}

1
喜欢这种方法。对于没有非空格字符的情况,它应该返回一个空的属性字符串。 - Michael Voong

3

Swift 4及以上版本

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)
    }
}

用途:

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

2

我做了一个Swift 3实现,以防有人感兴趣:

/**
 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()
    }
}

0

Swift 3.2 版本:

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)
        }
    }
}

-4

以下代码将适用于您的要求。

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

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

我应该如何准确获取范围? - Tommy Wei
尝试使用上述代码从属性字符串中删除前后空格。 - macpandit
上面的代码运行良好。但它会返回一个 String 而不是 NSAttributedString。你只需要将 String 转换成 NSAttributedString 就可以了。只需要两行漂亮的代码。 - Bhautik Ziniya
5
如果您将其转换为字符串,然后再转回属性字符串,它的属性将会消失。 - Tommy Wei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接