Добавление атрибутов в строку с помощью смайликов нарушает некоторые смайлики

Когда я пытаюсь добавить атрибуты к атрибутной строке, которая содержит эмодзи, иногда некоторые смайлики нарушаются. Для обычного текста работает отлично. Есть идеи, что я делаю не так?

Вот моя функция - она ​​должна выделять жирным шрифтом цитаты (текст между первой и последней кавычкой)

func boldQuotation(str: String, fontSize: CGFloat) -> NSAttributedString {
    let normalAttributes = [NSFontAttributeName : UIFont.systemFontOfSize(fontSize)]
    let boldAttributes = [NSFontAttributeName : UIFont.boldSystemFontOfSize(fontSize)]
    let attributedStr = NSMutableAttributedString(string: str, attributes: normalAttributes)

    let firstQuotationMarkRange = str.rangeOfString("\"")
    let lastQuotationMarkRange  = str.rangeOfString("\"", options: [.BackwardsSearch], range: nil, locale: nil)
    guard let firstIndex = firstQuotationMarkRange?.startIndex, lastIndex = lastQuotationMarkRange?.endIndex else {
        return attributedStr
    }
    attributedStr.addAttributes(boldAttributes, range: NSMakeRange(str.startIndex.distanceTo(firstIndex), firstIndex.distanceTo(lastIndex)))
    return attributedStr
}

Вот образец текста, который не может быть правильно приписан:

let str = "\"\""

Результат выглядит так:

Я использую Swift 2.3, iOS 10.2.1, Xcode 8.2.1, цель развертывания: 9.3

1 ответ

Хорошо, после дальнейшего исследования (и без ответа) я наконец нашел причину и решение этой ошибки.

Возникла проблема с созданием NSRange используя индексы Range (получен из String). Короче говоря - Свифт String диапазоны и NSString диапазоны не должны использоваться для преобразования одного в другое. По крайней мере, не так:

let firstQuotationMarkRange     = str.rangeOfString("\"")
let lastQuotationMarkRange      = str.rangeOfString("\"", options: [.BackwardsSearch], range: nil, locale: nil)
guard let firstIndex = firstQuotationMarkRange?.startIndex, lastIndex = lastQuotationMarkRange?.endIndex else {
        return attributedStr
    }
//THIS IS WRONG:
range = NSMakeRange(str.startIndex.distanceTo(firstIndex), firstIndex.distanceTo(lastIndex))

Так каково правильное решение? Сначала преобразуйте строку в строку NSString, а затем начните искать диапазон подстроки. Здесь исправлена ​​функция:

func boldQuotation(str: String, fontSize: CGFloat) -> NSAttributedString {
    let normalAttributes = [NSFontAttributeName : UIFont.systemFontOfSize(fontSize)]
    let boldAttributes = [NSFontAttributeName : UIFont.boldSystemFontOfSize(fontSize)]
    let attributedStr = NSMutableAttributedString(string: str, attributes: normalAttributes)

    let nsStr = str as NSString
    let firstQuotationMarkRange = nsStr.rangeOfString("\"")
    let lastQuotationMarkRange  = nsStr.rangeOfString("\"", options: [.BackwardsSearch])
    guard firstQuotationMarkRange.length > 0 && lastQuotationMarkRange.length > 0 else {
        return attributedStr
    }
    let nsrange = NSMakeRange(firstQuotationMarkRange.location, lastQuotationMarkRange.location + lastQuotationMarkRange.length - firstQuotationMarkRange.location)
    attributedStr.addAttributes(boldAttributes, range: nsrange)
    return attributedStr
}

Решено благодаря этому сообщению: NSRange от Swift Range

Другие вопросы по тегам