Problema: NSAttributedString toma un NSRange mientras uso una cadena Swift que usa Range
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)
}
})
Produce el siguiente error:
error: 'Range' no es convertible a 'NSRange' attributeString.addAttribute (NSForegroundColorAttributeName, valor: NSColor.redColor (), range: substringRange)
Respuestas:
Los
String
rangos rápidos y losNSString
rangos no son "compatibles". Por ejemplo, un emoji como 😄 cuenta como un personaje Swift, pero como dosNSString
caracteres (un par sustituto llamado UTF-16).Por lo tanto, su solución sugerida producirá resultados inesperados si la cadena contiene dichos caracteres. Ejemplo:
Salida:
Como puede ver, "ph say" ha sido marcado con el atributo, no "diciendo".
Como en
NS(Mutable)AttributedString
última instancia requiere unaNSString
y unaNSRange
, en realidad es mejor convertirNSString
primero la cadena dada . Entonces elsubstringRange
es unNSRange
y ya no tienes que convertir los rangos:Salida:
Actualización para Swift 2:
Actualización para Swift 3:
Actualización para Swift 4:
A partir de Swift 4 (Xcode 9), la biblioteca estándar de Swift proporciona un método para convertir entre
Range<String.Index>
yNSRange
. La conversión aNSString
ya no es necesaria:Aquí
substringRange
hay unRange<String.Index>
, y que se convierte al correspondienteNSRange
confuente
Range<String.Index>
yNSString
no son compatibles. ¿Son sus contrapartes también incompatibles? Es decir, sonNSRange
yString
incompatibles? Porque una de las API de Apple combina específicamente las dos: coincidencias (en: opciones: rango :)Para casos como el que describiste, encontré que esto funciona. Es relativamente corto y dulce:
fuente
NSRange
.str
es unNSString
y por lo tantostr.RangeOfString()
devuelve unNSRange
.let str = attributedString.string as NSString
Las respuestas están bien, pero con Swift 4 podría simplificar un poco su código:
Tenga cuidado, ya que el resultado de la
range
función debe desenvolverse.fuente
Solución posible
Swift proporciona la distancia () que mide la distancia entre el inicio y el final que se puede usar para crear un NSRange:
fuente
Para mí esto funciona perfectamente:
fuente
Swift 4:
Claro, sé que Swift 4 ya tiene una extensión para NSRange
Sé que en la mayoría de los casos este init es suficiente. Ver su uso:
Pero la conversión se puede hacer directamente desde Range <String.Index> a NSRange sin la instancia de Strift de Swift.
En lugar del uso de inicio genérico que requiere de usted el parámetro de destino como Cadena y si no tiene una cadena de destino a mano, puede crear la conversión directamente
o puede crear la extensión especializada para Range
Uso:
o
Swift 5:
Debido a la migración de las cadenas Swift a la codificación UTF-8 de forma predeterminada, el uso de
encodedOffset
se considera obsoleto y Range no se puede convertir a NSRange sin una instancia de String, porque para calcular el desplazamiento necesitamos la cadena fuente que es codificado en UTF-8 y debe convertirse a UTF-16 antes de calcular el desplazamiento. Entonces, el mejor enfoque, por ahora, es usar init genérico .fuente
encodedOffset
se considera perjudicial y quedará en desuso .Swift 4
Creo que hay dos formas.
1. NSRange (rango, en:)
2. NSRange (ubicación :, longitud:)
Código de muestra:
Captura de pantalla:
fuente
encodedOffset
se considera perjudicial y quedará en desuso .Variante de extensión Swift 3 que conserva los atributos existentes.
fuente
fuente
Me encanta el lenguaje Swift, pero usarlo
NSAttributedString
con un SwiftRange
que no es compatible meNSRange
ha dolido mucho la cabeza. Entonces, para evitar toda esa basura, ideé los siguientes métodos para devolver unNSMutableAttributedString
con las palabras resaltadas establecidas con su color.Esto no funciona para emojis. Modifique si debe hacerlo.
Uso:
fuente
fuente