patternswiftMinor
Chop off trailing newline for Swift's NSAttributedString
Viewed 0 times
swiftnewlinensattributedstringchopfortrailingoff
Problem
I've made this extension but I'm touchy around
NSAttributedStrings, keenly aware that Swift refuses to use the traditional notion of integer lengths on Unicode Strings, what with their graphemes that can compose and overlap. Also, it feels odd to convert to String to check for the newline. I'm not worried about \r because \n is the standard conversion when coming from HTML
tags. Also is this too long for something so simple? It feels like I'm missing someethingextension NSAttributedString {
var trailingNewlineChopped: NSAttributedString {
get {
guard self.length > 0 else {
return self
}
let lastCharRange = NSMakeRange(self.length - 1, 1)
let lastChar = self.attributedSubstringFromRange(lastCharRange).string
guard lastChar == "\n" else {
return self
}
let mutableCopy = NSMutableAttributedString(attributedString: self)
mutableCopy.deleteCharactersInRange(lastCharRange)
return mutableCopy
}
}
}Solution
Your method works correctly, as far as I can see.
For a read-only computed property, you don't need to enclose the
getter method in
Checking for a trailing newline character can be done with
the
Instead of creating a mutable copy and removing the last character,
you can extract the first
The method then becomes
You can even omit the implicit
preference:
be a good idea to start replacing that by
Update: Swift 3 changed how Objective-C methods are imported
into Swift:
For a read-only computed property, you don't need to enclose the
getter method in
get { }:var trailingNewlineChopped: NSAttributedString {
guard self.length > 0 else {
return self
}
let lastCharRange = NSMakeRange(self.length - 1, 1)
let lastChar = self.attributedSubstringFromRange(lastCharRange).string
guard lastChar == "\n" else {
return self
}
let mutableCopy = NSMutableAttributedString(attributedString: self)
mutableCopy.deleteCharactersInRange(lastCharRange)
return mutableCopy
}Checking for a trailing newline character can be done with
the
hasSuffix() method on the underlying string.Instead of creating a mutable copy and removing the last character,
you can extract the first
length-1 characters instead.The method then becomes
var trailingNewlineChopped: NSAttributedString {
if self.string.hasSuffix("\n") {
return self.attributedSubstringFromRange(NSMakeRange(0, self.length - 1))
} else {
return self
}
}You can even omit the implicit
self., but that is a matter of personalpreference:
var trailingNewlineChopped: NSAttributedString {
if string.hasSuffix("\n") {
return self.attributedSubstringFromRange(NSMakeRange(0, length - 1))
} else {
return self
}
}NSMakeRange will not be available in Swift 3 anymore, so it couldbe a good idea to start replacing that by
NSRange(location:, length:) in your code.Update: Swift 3 changed how Objective-C methods are imported
into Swift:
extension NSAttributedString {
var trailingNewlineChopped: NSAttributedString {
if string.hasSuffix("\n") {
return self.attributedSubstring(from: NSRange(location: 0, length: length - 1))
} else {
return self
}
}
}Code Snippets
var trailingNewlineChopped: NSAttributedString {
guard self.length > 0 else {
return self
}
let lastCharRange = NSMakeRange(self.length - 1, 1)
let lastChar = self.attributedSubstringFromRange(lastCharRange).string
guard lastChar == "\n" else {
return self
}
let mutableCopy = NSMutableAttributedString(attributedString: self)
mutableCopy.deleteCharactersInRange(lastCharRange)
return mutableCopy
}var trailingNewlineChopped: NSAttributedString {
if self.string.hasSuffix("\n") {
return self.attributedSubstringFromRange(NSMakeRange(0, self.length - 1))
} else {
return self
}
}var trailingNewlineChopped: NSAttributedString {
if string.hasSuffix("\n") {
return self.attributedSubstringFromRange(NSMakeRange(0, length - 1))
} else {
return self
}
}extension NSAttributedString {
var trailingNewlineChopped: NSAttributedString {
if string.hasSuffix("\n") {
return self.attributedSubstring(from: NSRange(location: 0, length: length - 1))
} else {
return self
}
}
}Context
StackExchange Code Review Q#139461, answer score: 8
Revisions (0)
No revisions yet.