Comment puis-je concaténer NSAttributedStrings?

159

J'ai besoin de rechercher des chaînes et de définir certains attributs avant de fusionner les chaînes, donc avoir NSStrings -> Concaténer -> Make NSAttributedString n'est pas une option, existe-t-il un moyen de concaténer attribuéString à un autre attribuéString?

Imanou Petit
la source
13
Il est ridicule de voir à quel point cela est encore difficile en août 2016.
Wedge Martin
17
Même en 2018 ...
DehMotth
11
toujours en 2019;)
raistlin
8
toujours en 2020 ...
Hwangho Kim

Réponses:

210

Je vous recommande d'utiliser une seule chaîne attribuée mutable, suggérée par @Linuxios, et voici un autre exemple de cela:

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];

Cependant, juste pour obtenir toutes les options disponibles, vous pouvez également créer une seule chaîne attribuée mutable, faite à partir d'une NSString formatée contenant les chaînes d'entrée déjà assemblées. Vous pouvez ensuite utiliser addAttributes: range:pour ajouter les attributs après coup aux plages contenant les chaînes d'entrée. Je recommande cependant l'ancienne méthode.

Mick MacCallum
la source
Pourquoi recommandez-vous d'ajouter des chaînes au lieu d'ajouter des attributs?
ma11hew28
87

Si vous utilisez Swift, vous pouvez simplement surcharger l' +opérateur afin de pouvoir les concaténer de la même manière que vous concaténez des chaînes normales:

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

Vous pouvez maintenant les concaténer simplement en les ajoutant:

let helloworld = NSAttributedString(string: "Hello ") + NSAttributedString(string: "World")
algue
la source
5
la classe mutable est un sous-type de la classe immuable.
algal
4
Vous pouvez utiliser le sous-type mutable dans n'importe quel contexte qui attend le type parent immuable, mais pas l'inverse. Vous voudrez peut-être revoir le sous-classement et l'héritage.
algal
6
Oui, vous devriez faire une copie défensive si vous voulez être défensif. (Pas de sarcasme.)
algal
1
Si vous voulez vraiment retourner NSAttributedString, alors peut-être que cela fonctionnerait:return NSAttributedString(attributedString: result)
Alex
2
@ n13 Je créerais un dossier appelé Helpersou Extensionset mettrais cette fonction dans un fichier nommé NSAttributedString+Concatenate.swift.
David Lawson
34

Swift 3: créez simplement un NSMutableAttributedString et ajoutez-y les chaînes attribuées.

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
la source
25

Essaye ça:

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

astring1et astring2sont l' NSAttributedStringart.

Linuxios
la source
13
Ou [[aString1 mutableCopy] appendAttributedString: aString2].
JWWalker
@JWWalker votre 'oneliner' est corrompu. vous ne pouvez pas obtenir ce résultat de "concaténation" car appendAttributedString ne renvoie pas de chaîne. Même histoire avec les dictionnaires
gaussblurinc
@gaussblurinc: bon point, bien sûr, votre critique s'applique également à la réponse que nous commentons. Ça devrait être NSMutableAttributedString* aString3 = [aString1 mutableCopy]; [aString3 appendAttributedString: aString2];.
JWWalker
@gaussblurinc, JWalker: Correction de la réponse.
Linuxios
@Linuxios, aussi, vous revenez resultcomme NSMutableAttributedString. ce n'est pas ce que l'auteur veut voir. stringByAppendingString- cette méthode sera bonne
gaussblurinc
5

2020 | SWIFT 5.1:

Vous pouvez en ajouter 2 NSMutableAttributedStringde la manière suivante:

let concatenated = NSAttrStr1.append(NSAttrStr2)

Une autre façon fonctionne avec NSMutableAttributedStringet les NSAttributedStringdeux:

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

Une autre façon est ...

var full = NSAttrStr1 + NSAttrStr2 + NSAttrStr3

et:

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


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

Vous pouvez le faire avec l'extension suivante:

// 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
    }
}
Andrew
la source
2
J'utilise Swift 5.1 et je n'arrive pas à ajouter deux NSAttrStrings ensemble ...
PaulDoesDev
1
Étrange. Dans ce cas, utilisez simplementNSAttrStr1.append(NSAttrStr2)
Andrew
Mise à jour de ma réponse avec des extensions pour simplement ajouter deux NSAttrStrings :)
Andrew
4

Si vous utilisez des Cocoapods, une alternative aux deux réponses ci-dessus qui vous permet d'éviter la mutabilité dans votre propre code est d'utiliser l'excellente catégorie NSAttributedString + CCLFormat sur NSAttributedStrings qui vous permet d'écrire quelque chose comme:

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

Il utilise bien sûr juste NSMutableAttributedStringsous les couvertures.

Il a également l'avantage supplémentaire d'être une fonction de formatage à part entière - il peut donc faire beaucoup plus que d'ajouter des chaînes ensemble.

fatuhoku
la source
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
la source
1

Vous pouvez essayer SwiftyFormat Il utilise la syntaxe suivante

let format = "#{{user}} mentioned you in a comment. #{{comment}}"
let message = NSAttributedString(format: format,
                                 attributes: commonAttributes,
                                 mapping: ["user": attributedName, "comment": attributedComment])
Igor Palaguta
la source
1
Pouvez-vous s'il vous plaît en dire plus, comment sa volonté fonctionnera-t-elle?
Kandhal Bhutiya