Jay*_*Jay 153 macos ios nsrange swift
问题:当我使用使用Range的Swift String时,NSAttributedString接受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)
}
})
Run Code Online (Sandbox Code Playgroud)
产生以下错误:
错误:'Range'不能转换为'NSRange'aligolsString.addAttribute(NSForegroundColorAttributeName,value:NSColor.redColor(),range:substringRange)
Mar*_*n R 241
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)
Run Code Online (Sandbox Code Playgroud)
输出:
Long paragra{
}ph say{
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}ing!{
}
如你所见,"ph say"已经标有属性,而不是"说".
由于NS(Mutable)AttributedString最终需要a NSString和a NSRange,实际上最好将给定的字符串转换为NSString第一个.然后substringRange
是一个NSRange,您不必再转换范围:
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)
Run Code Online (Sandbox Code Playgroud)
输出:
Long paragraph {
}saying{
NSColor = "NSCalibratedRGBColorSpace 1 0 0 1";
}!{
}
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)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
这substringRange是一个Range<String.Index>,并将其转换为相应NSRange的
NSRange(substringRange, in: text)
Run Code Online (Sandbox Code Playgroud)
roy*_*rma 53
对于像你描述的那样的情况,我发现这是有用的.它相对简短而且甜美:
let attributedString = NSMutableAttributedString(string: "follow the yellow brick road") //can essentially come from a textField.text as well (will need to unwrap though)
let text = "follow the yellow brick road"
let str = NSString(string: text)
let theRange = str.rangeOfString("yellow")
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.yellowColor(), range: theRange)
Run Code Online (Sandbox Code Playgroud)
Geo*_*dze 23
答案很好,但使用Swift 4可以简化代码:
let text = "Test string"
let substring = "string"
let substringRange = text.range(of: substring)!
let nsRange = NSRange(substringRange, in: text)
Run Code Online (Sandbox Code Playgroud)
请注意,因为range功能的结果必须打开.
Jay*_*Jay 10
可能解决方案
Swift提供distance(),用于测量可用于创建NSRange的start和end之间的距离:
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
let start = distance(text.startIndex, substringRange.startIndex)
let length = distance(substringRange.startIndex, substringRange.endIndex)
let range = NSMakeRange(start, length)
// println("word: \(substring) - \(d1) to \(d2)")
if (substring == "saying") {
attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: range)
}
})
Run Code Online (Sandbox Code Playgroud)
斯威夫特 5 解决方案
将范围转换为 NSRange
由于'encodedOffset'已被弃用,因此现在为了将String.Index转换为Int ,我们需要派生Range<String.Index>的原始字符串的引用。
NSRange 的方便详细扩展如下:
extension NSRange {
public init(range: Range<String.Index>,
originalText: String) {
let range_LowerBound_INDEX = range.lowerBound
let range_UpperBound_INDEX = range.upperBound
let range_LowerBound_INT = range_LowerBound_INDEX.utf16Offset(in: originalText)
let range_UpperBound_INT = range_UpperBound_INDEX.utf16Offset(in: originalText)
let locationTemp = range_LowerBound_INT
let lengthTemp = range_UpperBound_INT - range_LowerBound_INT
self.init(location: locationTemp,
length: lengthTemp)
}
}
Run Code Online (Sandbox Code Playgroud)
虽然简写扩展如下
extension NSRange {
public init(range: Range<String.Index>,
originalText: String) {
self.init(location: range.lowerBound.utf16Offset(in: originalText),
length: range.upperBound.utf16Offset(in: originalText) - range.lowerBound.utf16Offset(in: originalText))
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用任何 Range 将其转换为 NSRange,如下所示,分享我自己的要求,这导致我编写了上面的扩展
我使用下面的字符串扩展来查找字符串中特定单词的所有范围
extension String {
func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] {
var ranges: [Range<Index>] = []
while let range = range(of: substring, options: options, range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale) {
ranges.append(range)
}
return ranges
}
}
Run Code Online (Sandbox Code Playgroud)
我的要求是更改字符串中特定单词的颜色,因此我编写了这个扩展来完成这项工作
extension NSAttributedString {
static func colored(originalText:String,
wordToColor:String,
currentColor:UIColor,
differentColor:UIColor) -> NSAttributedString {
let attr = NSMutableAttributedString(string: originalText)
attr.beginEditing()
attr.addAttribute(NSAttributedString.Key.foregroundColor,
value: currentColor,
range: NSRange(location: 0, length: originalText.count))
// FOR COVERING ALL THE OCCURENCES
for eachRange in originalText.ranges(of: wordToColor) {
attr.addAttribute(NSAttributedString.Key.foregroundColor,
value: differentColor,
range: NSRange(range: eachRange, originalText: originalText))
}
attr.endEditing()
return attr
}
}
Run Code Online (Sandbox Code Playgroud)
最后我从我的主要代码中使用它,如下所示
let text = "Collected".localized() + " + " + "Cancelled".localized() + " + " + "Pending".localized()
myLabel.attributedText = NSAttributedString.colored(originalText: text,
wordToColor: "+",
currentColor: UIColor.purple,
differentColor: UIColor.blue)
Run Code Online (Sandbox Code Playgroud)
结果如下,+号的颜色从紫色的正文颜色变成了蓝色。
希望这可以帮助有需要的人。谢谢!
小智 6
对我来说,这很完美:
let font = UIFont.systemFont(ofSize: 12, weight: .medium)
let text = "text"
let attString = NSMutableAttributedString(string: "exemple text :)")
attString.addAttributes([.font: font], range:(attString.string as NSString).range(of: text))
label.attributedText = attString
Run Code Online (Sandbox Code Playgroud)
斯威夫特4:
当然,我知道Swift 4已经扩展了NSRange
public init<R, S>(_ region: R, in target: S) where R : RangeExpression,
S : StringProtocol,
R.Bound == String.Index, S.Index == String.Index
Run Code Online (Sandbox Code Playgroud)
我知道在大多数情况下这个初始化就足够了.看它的用法:
let string = "Many animals here: !!!"
if let range = string.range(of: ""){
print((string as NSString).substring(with: NSRange(range, in: string))) // ""
}
Run Code Online (Sandbox Code Playgroud)
但转换可以直接从Range <String.Index>到NSRange完成而不需要Swift的String实例.
而不是通用的init用法,它要求您将目标参数作为String,如果您没有目标字符串,则可以直接创建转换
extension NSRange {
public init(_ range:Range<String.Index>) {
self.init(location: range.lowerBound.encodedOffset,
length: range.upperBound.encodedOffset -
range.lowerBound.encodedOffset) }
}
Run Code Online (Sandbox Code Playgroud)
或者您可以为Range本身创建专门的扩展
extension Range where Bound == String.Index {
var nsRange:NSRange {
return NSRange(location: self.lowerBound.encodedOffset,
length: self.upperBound.encodedOffset -
self.lowerBound.encodedOffset)
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
let string = "Many animals here: !!!"
if let range = string.range(of: ""){
print((string as NSString).substring(with: NSRange(range))) // ""
}
Run Code Online (Sandbox Code Playgroud)
要么
if let nsrange = string.range(of: "")?.nsRange{
print((string as NSString).substring(with: nsrange)) // ""
}
Run Code Online (Sandbox Code Playgroud)
雨燕4
我认为,有两种方法。
1. NSRange(范围,在: )
2. NSRange(位置:,长度:)
示例代码:
let attributedString = NSMutableAttributedString(string: "Sample Text 12345", attributes: [.font : UIFont.systemFont(ofSize: 15.0)])
// NSRange(range, in: )
if let range = attributedString.string.range(of: "Sample") {
attributedString.addAttribute(.foregroundColor, value: UIColor.orange, range: NSRange(range, in: attributedString.string))
}
// NSRange(location: , length: )
if let range = attributedString.string.range(of: "12345") {
attributedString.addAttribute(.foregroundColor, value: UIColor.green, range: NSRange(location: range.lowerBound.encodedOffset, length: range.upperBound.encodedOffset - range.lowerBound.encodedOffset))
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
108674 次 |
| 最近记录: |