🎨
[Swift] AttributedStringで該当する部分全てを修飾する
iOS15から使えるAttributedString
のサンプルコードにこういうのがあります。
var attributedString = AttributedString("This is a basic string that contains a link.")
let range = attributedString.range(of: "link")!
attributedString[range].link = URL(string: "https://www.example.com")
ところが、linkという文字列が複数ある場合はこの方法では動きません。range
は連続するインデックスしか扱えないので、複数の部分を一度に扱うことはできないからです。
解決方法
以下の通りでいけます。
// attributedStringをsubstringに変換する
var substring = attributedString[attributedString.startIndex ..< attributedString.endIndex]
while let range = substring.range(of: "key") {
// ここでattributedString[range]の処理を行う
// 処理した部分の後の部分をsubstringに代入する
substring = attributedString[range.upperBound...]
}
extensionにしておきましょう。
extension AttributedString {
func ranges<T: StringProtocol>(of stringToFind: T) -> [Range<AttributedString.Index>] {
var ranges: [Range<AttributedString.Index>] = []
var substring = self[self.startIndex ..< self.endIndex]
while let range = substring.range(of: stringToFind) {
ranges.append(range)
substring = self[range.upperBound...]
}
return ranges
}
}
これでいつでも全range
を取れるようになったので、あとは煮るなり焼くなりお好きにしてください。
Discussion