¿Cómo puedo concatenar NSAttributedStrings?

159

Necesito buscar algunas cadenas y establecer algunos atributos antes de fusionar las cadenas, por lo que tener NSStrings -> Concatenarlos -> Hacer NSAttributedString no es una opción, ¿hay alguna forma de concatenar atribuString a otra atribuString?

Imanou Petit
fuente
13
Es ridículo lo difícil que sigue siendo esto en agosto de 2016.
Wedge Martin
17
Incluso en 2018 ...
DehMotth
11
todavía en 2019;)
raistlin
8
todavía en 2020 ...
Hwangho Kim

Respuestas:

210

Le recomiendo que use una sola cadena atribuida mutable que sugirió @Linuxios, y aquí hay otro ejemplo de eso:

NSMutableAttributedString *mutableAttString = [[NSMutableAttributedString alloc] init];

NSString *plainString = // ...
NSDictionary *attributes = // ... a dictionary with your attributes.
NSAttributedString *newAttString = [[NSAttributedString alloc] initWithString:plainString attributes:attributes];

[mutableAttString appendAttributedString:newAttString];

Sin embargo, solo por el hecho de obtener todas las opciones, también puede crear una sola cadena atribuida mutable, hecha de una NSString formateada que contenga las cadenas de entrada ya juntas. Luego puede usar addAttributes: range:para agregar los atributos después del hecho a los rangos que contienen las cadenas de entrada. Sin embargo, recomiendo la forma anterior.

Mick MacCallum
fuente
¿Por qué recomienda agregar cadenas en lugar de agregar atributos?
ma11hew28
87

Si está utilizando Swift, puede sobrecargar el +operador para que pueda concatenarlos de la misma manera que concatena cadenas normales:

// concatenate attributed strings
func + (left: NSAttributedString, right: NSAttributedString) -> NSAttributedString
{
    let result = NSMutableAttributedString()
    result.append(left)
    result.append(right)
    return result
}

Ahora puede concatenarlos simplemente agregándolos:

let helloworld = NSAttributedString(string: "Hello ") + NSAttributedString(string: "World")
alga
fuente
55
la clase mutable es un subtipo de la clase inmutable.
algas
44
Puede usar el subtipo mutable en cualquier contexto que espere el tipo padre inmutable pero no al revés. Es posible que desee revisar las subclases y la herencia.
algal
66
Sí, debe hacer una copia defensiva si quiere estar a la defensiva. (No sarcasmo.)
algas
1
Si realmente desea devolver NSAttributedString, entonces quizás esto funcionaría:return NSAttributedString(attributedString: result)
Alex
2
@ n13 Crearía una carpeta llamada Helperso Extensionsy pondría esta función en un archivo llamado NSAttributedString+Concatenate.swift.
David Lawson el
34

Swift 3: simplemente cree una NSMutableAttributedString y añádales las cadenas atribuidas.

let mutableAttributedString = NSMutableAttributedString()

let boldAttribute = [
    NSFontAttributeName: UIFont(name: "GothamPro-Medium", size: 13)!,
    NSForegroundColorAttributeName: Constants.defaultBlackColor
]

let regularAttribute = [
    NSFontAttributeName: UIFont(name: "Gotham Pro", size: 13)!,
    NSForegroundColorAttributeName: Constants.defaultBlackColor
]

let boldAttributedString = NSAttributedString(string: "Warning: ", attributes: boldAttribute)
let regularAttributedString = NSAttributedString(string: "All tasks within this project will be deleted.  If you're sure you want to delete all tasks and this project, type DELETE to confirm.", attributes: regularAttribute)
mutableAttributedString.append(boldAttributedString)
mutableAttributedString.append(regularAttributedString)

descriptionTextView.attributedText = mutableAttributedString

swift5 upd:

    let captionAttribute = [
        NSAttributedString.Key.font: Font.captionsRegular,
        NSAttributedString.Key.foregroundColor: UIColor.appGray
    ]
Josh O'Connor
fuente
25

Prueba esto:

NSMutableAttributedString* result = [astring1 mutableCopy];
[result appendAttributedString:astring2];

Donde astring1y astring2son NSAttributedStrings.

Linuxios
fuente
13
O [[aString1 mutableCopy] appendAttributedString: aString2].
JWWalker
@JWWalker tu 'oneliner' está dañado. no puede obtener este resultado de "concatenación" porque appendAttributedString no devuelve una cadena. Misma historia con los diccionarios
gaussblurinc
@gaussblurinc: buen punto, por supuesto, su crítica también se aplica a la respuesta que estamos comentando. Debería ser NSMutableAttributedString* aString3 = [aString1 mutableCopy]; [aString3 appendAttributedString: aString2];.
JWWalker
@gaussblurinc, JWalker: corrigió la respuesta.
Linuxios
@Linuxios, también, regresas resultcomo NSMutableAttributedString. No es lo que el autor quiere ver. stringByAppendingString- este método será bueno
gaussblurinc
5

2020 | SWIFT 5.1:

Puede agregar 2 NSMutableAttributedStringde la siguiente manera:

let concatenated = NSAttrStr1.append(NSAttrStr2)

Otra forma funciona con NSMutableAttributedStringy NSAttributedStringambos:

[NSAttrStr1, NSAttrStr2].joinWith(separator: "")

Otra forma es ...

var full = NSAttrStr1 + NSAttrStr2 + NSAttrStr3

y:

var full = NSMutableAttributedString(string: "hello ")
// NSAttrStr1 == 1


full += NSAttrStr1 // full == "hello 1"       
full += " world"   // full == "hello 1 world"

Puede hacer esto con la siguiente extensión:

// works with NSAttributedString and NSMutableAttributedString!
public extension NSAttributedString {
    static func + (left: NSAttributedString, right: NSAttributedString) -> NSAttributedString {
        let leftCopy = NSMutableAttributedString(attributedString: left)
        leftCopy.append(right)
        return leftCopy
    }

    static func + (left: NSAttributedString, right: String) -> NSAttributedString {
        let leftCopy = NSMutableAttributedString(attributedString: left)
        let rightAttr = NSMutableAttributedString(string: right)
        leftCopy.append(rightAttr)
        return leftCopy
    }

    static func + (left: String, right: NSAttributedString) -> NSAttributedString {
        let leftAttr = NSMutableAttributedString(string: left)
        leftAttr.append(right)
        return leftAttr
    }
}

public extension NSMutableAttributedString {
    static func += (left: NSMutableAttributedString, right: String) -> NSMutableAttributedString {
        let rightAttr = NSMutableAttributedString(string: right)
        left.append(rightAttr)
        return left
    }

    static func += (left: NSMutableAttributedString, right: NSAttributedString) -> NSMutableAttributedString {
        left.append(right)
        return left
    }
}
Andrés
fuente
2
Estoy usando Swift 5.1 y parece que no puedo agregar dos NSAttrStrings juntos ...
PaulDoesDev
1
Extraño. En este caso solo useNSAttrStr1.append(NSAttrStr2)
Andrew
Actualicé mi respuesta con extensiones por solo agregar dos NSAttrStrings :)
Andrew
4

Si está utilizando Cocoapods, una alternativa a ambas respuestas anteriores que le permiten evitar la mutabilidad en su propio código es usar la excelente categoría NSAttributedString + CCLFormat en NSAttributedStrings que le permite escribir algo como:

NSAttributedString *first = ...;
NSAttributedString *second = ...;
NSAttributedString *combined = [NSAttributedString attributedStringWithFormat:@"%@%@", first, second];

Por supuesto, solo se usa NSMutableAttributedStringdebajo de las sábanas.

También tiene la ventaja adicional de ser una función de formato completa, por lo que puede hacer mucho más que agregar cadenas juntas.

fatuhoku
fuente
1
// Immutable approach
// class method

+ (NSAttributedString *)stringByAppendingString:(NSAttributedString *)append toString:(NSAttributedString *)string {
  NSMutableAttributedString *result = [string mutableCopy];
  [result appendAttributedString:append];
  NSAttributedString *copy = [result copy];
  return copy;
}

//Instance method
- (NSAttributedString *)stringByAppendingString:(NSAttributedString *)append {
  NSMutableAttributedString *result = [self mutableCopy];
  [result appendAttributedString:append];
  NSAttributedString *copy = [result copy];
  return copy;
}
gaussblurinc
fuente
1

Puedes probar SwiftyFormat. Utiliza la siguiente sintaxis

let format = "#{{user}} mentioned you in a comment. #{{comment}}"
let message = NSAttributedString(format: format,
                                 attributes: commonAttributes,
                                 mapping: ["user": attributedName, "comment": attributedComment])
Igor Palaguta
fuente
1
¿Puedes por favor elaborarlo más? ¿Cómo funciona su voluntad?
Kandhal Bhutiya