Skip to content

Instantly share code, notes, and snippets.

@shawnthroop
Last active April 18, 2018 15:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawnthroop/93a184378d1b7e7bdbb2a4ec9e893b68 to your computer and use it in GitHub Desktop.
Save shawnthroop/93a184378d1b7e7bdbb2a4ec9e893b68 to your computer and use it in GitHub Desktop.
Adjusting ranges retrieved from an API (App.net, pnut.io, etc.) for use with NSAttributedString
// Swift 4.0.3
import Foundation
extension NSRange: SurrogatePairAdjustable {
func adjusted(for pairs: [String.SurrogatePair]) -> NSRange {
if pairs.isEmpty {
return self
}
var adjusted = self
for pair in pairs {
if pair.index <= NSMaxRange(adjusted) {
if pair.index < adjusted.location {
adjusted.location += pair.offset
} else {
adjusted.length += pair.offset
}
}
}
return adjusted
}
}
// Swift 4.0.3
extension String {
struct SurrogatePair {
var index: Int
var offset: IndexDistance
}
var surrogatePairs: [SurrogatePair] {
return surrogatePairs(upTo: endIndex)
}
func surrogatePairs(upTo end: Index) -> [SurrogatePair] {
if isEmpty || end <= startIndex {
return []
}
var pairs: [SurrogatePair] = []
var idx: Int = 0
for char in self[..<end] {
let offset = char.unicodeScalars.offsetToUTF16
if offset > 0 {
pairs.append(SurrogatePair(index: idx, offset: offset))
}
idx += 1
}
return pairs
}
}
extension String.SurrogatePair: Hashable {
var hashValue: Int {
return index.hashValue ^ offset.hashValue
}
static func ==(lhs: String.SurrogatePair, rhs: String.SurrogatePair) -> Bool {
return lhs.index == rhs.index && lhs.offset == rhs.offset
}
}
private extension Character.UnicodeScalarView {
var offsetToUTF16: IndexDistance {
return reduce(into: 0, { $0 += $1.utf16.count - 1 })
}
}
// Swift 4.0.3
/// A type which can be adjusted to accomidate SurrogatePairs.
protocol SurrogatePairAdjustable {
func adjusted(for pairs: [String.SurrogatePair]) -> Self
}
extension SurrogatePairAdjustable {
mutating func adjust(for pairs: [String.SurrogatePair]) {
self = adjusted(for: pairs)
}
}
extension Sequence where Iterator.Element: SurrogatePairAdjustable {
func adjusted(for pairs: [String.SurrogatePair]) -> [Iterator.Element] {
return map { $0.adjusted(for: pairs) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment