1. ホーム
  2. ios

[解決済み】Swift RangeからNSRange?

2022-04-21 13:20:23

質問

問題あり。 NSAttributedStringはNSRangeを取るが、Rangeを使うSwift Stringを使用している

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) です。

どのように解決するのですか?

スウィフト String の範囲と NSString の範囲は互換性がありません。 たとえば、?のような絵文字は1つのSwift文字としてカウントされますが、2つの 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)

出力します。

?長いパラグラ{?
}ph say{
    NSColor = "NSCalibratedRGBColorSpace 1 0 0 1"。
}ing!
}

ご覧の通り、"ph say"に属性が付与され、"saying"には付与されていない。

以来 NS(Mutable)AttributedString 最終的には NSStringNSRange というのは、実は に変換したほうがよいでしょう。 NSString を最初に指定します。それから substringRangeNSRange で、もうレンジを変換する必要はありません。

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)

出力します。

?長い段落{?
と言っている。
    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)

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)