ios - 来自 Swift Range 的 NSRange?

标签 ios macos swift nsrange

问题: NSAttributedString 在我使用使用 Range 的 Swift String 时采用 NSRange

let text = "Long paragraph saying something goes here!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)

text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in

    if (substring == "saying") {
        attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
    }
})

产生以下错误:

error: 'Range' is not convertible to 'NSRange' attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)

最佳答案

swift String范围和 NSString范围不“兼容”。 例如,像😄这样的表情符号算作一个 Swift 字符,但算作两个 NSString。 字符(所谓的 UTF-16 代理对)。

因此,如果字符串 包含这样的字符。示例:

let text = "😄😄😄Long paragraph saying!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)

text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
    let start = distance(text.startIndex, substringRange.startIndex)
    let length = distance(substringRange.startIndex, substringRange.endIndex)
    let range = NSMakeRange(start, length)

    if (substring == "saying") {
        attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: range)
    }
})
println(attributedString)

输出:

😄😄😄Long paragra{
}ph say{
    NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}ing!{
}

As you see, "ph say" has been marked with the attribute, not "saying".

Since NS(Mutable)AttributedString ultimately requires an NSString and an NSRange, it is actually better to convert the given string to NSString first. Then the substringRange is an NSRange and you don't have to convert the ranges anymore:

let text = "😄😄😄Long paragraph saying!"
let nsText = text as NSString
let textRange = NSMakeRange(0, nsText.length)
let attributedString = NSMutableAttributedString(string: nsText)

nsText.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in

    if (substring == "saying") {
        attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
    }
})
println(attributedString)

输出:

😄😄😄Long paragraph {
}saying{
    NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}!{
}

Update for Swift 2:

let text = "😄😄😄Long paragraph saying!"
let nsText = text as NSString
let textRange = NSMakeRange(0, nsText.length)
let attributedString = NSMutableAttributedString(string: text)

nsText.enumerateSubstringsInRange(textRange, options: .ByWords, usingBlock: {
    (substring, substringRange, _, _) in

    if (substring == "saying") {
        attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
    }
})
print(attributedString)

Swift 3 更新:

let text = "😄😄😄Long paragraph saying!"
let nsText = text as NSString
let textRange = NSMakeRange(0, nsText.length)
let attributedString = NSMutableAttributedString(string: text)

nsText.enumerateSubstrings(in: textRange, options: .byWords, using: {
    (substring, substringRange, _, _) in

    if (substring == "saying") {
        attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.red, range: substringRange)
    }
})
print(attributedString)

Swift 4 更新:

从 Swift 4 (Xcode 9) 开始,Swift 标准库 提供在 Range<String.Index> 之间转换的方法和 NSRange . 转换为 NSString不再需要:

let text = "😄😄😄Long paragraph saying!"
let attributedString = NSMutableAttributedString(string: text)

text.enumerateSubstrings(in: text.startIndex..<text.endIndex, options: .byWords) {
    (substring, substringRange, _, _) in
    if substring == "saying" {
        attributedString.addAttribute(.foregroundColor, value: NSColor.red,
                                      range: NSRange(substringRange, in: text))
    }
}
print(attributedString)

在这里substringRangeRange<String.Index> ,然后转换为 对应NSRange

NSRange(substringRange, in: text)

关于ios - 来自 Swift Range 的 NSRange?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27040924/

相关文章:

macos - 如何ping文件中的每个IP?

uitableview - Swift - UITableView 中的褪色单元格

ios - 没有 UI 的共享扩展

ios - FBFriendPickerViewController 中的自定义 UITable

ios - 在 UINavigationController 中覆盖向后滑动手势

windows - Meteor 作为 native OSX 或 Windows 8 应用程序

ios - 如何在 UITextView 中显示可点击的链接

ios - 如何从 iphone 的 uitextfield 中获取选定的文本?

ios - 如何添加联系人自定义应用程序帐户,如下图所示

swift - MacOS 应用程序菜单中第一项的名称是如何本地化的?