Wie kann ich NSAttributedStrings verketten?

158

Ich muss einige Zeichenfolgen durchsuchen und einige Attribute festlegen, bevor die Zeichenfolgen zusammengeführt werden. NSStrings -> Verketten - - NSAttributedString erstellen ist also keine Option. Gibt es eine Möglichkeit, AttributedString mit einem anderen AttributedString zu verketten?

Imanou Petit
quelle
12
Es ist lächerlich, wie schwierig dies im August 2016 noch ist.
Wedge Martin
16
Auch im Jahr 2018 ...
DehMotth
10
noch im Jahr 2019;)
Raistlin
7
noch im Jahr 2020 ...
Hwangho Kim

Antworten:

210

Ich würde empfehlen, dass Sie eine einzelne veränderbare zugeordnete Zeichenfolge verwenden, die von @Linuxios vorgeschlagen wurde, und hier ist ein weiteres Beispiel dafür:

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

Um jedoch alle Optionen verfügbar zu machen, können Sie auch eine einzelne veränderbare zugeordnete Zeichenfolge erstellen, die aus einem formatierten NSString besteht, der die bereits zusammengestellten Eingabezeichenfolgen enthält. Sie können dann addAttributes: range:die Attribute nachträglich zu den Bereichen hinzufügen, die die Eingabezeichenfolgen enthalten. Ich empfehle jedoch den früheren Weg.

Mick MacCallum
quelle
Warum empfehlen Sie, Zeichenfolgen anzuhängen, anstatt Attribute hinzuzufügen?
ma11hew28
86

Wenn Sie Swift verwenden, können Sie den +Operator einfach überladen , damit Sie ihn auf dieselbe Weise verketten können, wie Sie normale Zeichenfolgen verketten:

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

Jetzt können Sie sie verketten, indem Sie sie hinzufügen:

let helloworld = NSAttributedString(string: "Hello ") + NSAttributedString(string: "World")
Algen
quelle
5
Die veränderbare Klasse ist ein Subtyp der unveränderlichen Klasse.
Algen
4
Sie können den veränderlichen Subtyp in jedem Kontext verwenden, der den unveränderlichen übergeordneten Typ erwartet, aber nicht umgekehrt. Möglicherweise möchten Sie die Unterklassen und die Vererbung überprüfen.
Algen
6
Ja, Sie sollten eine defensive Kopie erstellen, wenn Sie defensiv sein möchten. (Kein Sarkasmus.)
Algen
1
Wenn Sie wirklich NSAttributedString zurückgeben möchten, dann würde dies vielleicht funktionieren:return NSAttributedString(attributedString: result)
Alex
2
@ n13 Ich würde einen Ordner namens Helpersoder erstellen Extensionsund diese Funktion in eine Datei mit dem Namen einfügen NSAttributedString+Concatenate.swift.
David Lawson
34

Swift 3: Erstellen Sie einfach einen NSMutableAttributedString und hängen Sie die zugewiesenen Zeichenfolgen an diese an.

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
quelle
25

Versuche dies:

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

Wo astring1und astring2sind NSAttributedStrings.

Linuxios
quelle
13
Oder [[aString1 mutableCopy] appendAttributedString: aString2].
JWWalker
@JWWalker dein 'Oneliner' ist beschädigt. Sie können dieses "Verkettungs" -Ergebnis nicht erhalten, da appendAttributedString keine Zeichenfolge zurückgibt. Gleiche Geschichte mit Wörterbüchern
Gaussblurinc
@gaussblurinc: Guter Punkt, natürlich gilt Ihre Kritik auch für die Antwort, die wir kommentieren. Es sollte sein NSMutableAttributedString* aString3 = [aString1 mutableCopy]; [aString3 appendAttributedString: aString2];.
JWWalker
@gaussblurinc, JWalker: Die Antwort wurde korrigiert.
Linuxios
@Linuxios, auch Sie kehren zurück resultals NSMutableAttributedString. es ist nicht das, was der Autor sehen will. stringByAppendingString- Diese Methode wird gut sein
Gaussblurinc
5

2020 | SWIFT 5.1:

Sie können 2 NSMutableAttributedStringauf folgende Weise hinzufügen :

let concatenated = NSAttrStr1.append(NSAttrStr2)

Ein anderer Weg funktioniert mit NSMutableAttributedStringund NSAttributedStringbeidem:

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

Ein anderer Weg ist ....

var full = NSAttrStr1 + NSAttrStr2 + NSAttrStr3

und:

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


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

Sie können dies mit der folgenden Erweiterung tun:

// 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
quelle
2
Ich verwende Swift 5.1 und kann nicht einfach zwei NSAttrStrings zusammenfügen ...
PaulDoesDev
1
Seltsam. In diesem Fall verwenden Sie einfachNSAttrStr1.append(NSAttrStr2)
Andrew
Aktualisierte meine Antwort mit Erweiterungen für das Hinzufügen von nur zwei NSAttrStrings :)
Andrew
4

Wenn Sie Cocoapods verwenden, besteht eine Alternative zu den beiden oben genannten Antworten, mit denen Sie die Veränderlichkeit Ihres eigenen Codes vermeiden können, darin, die ausgezeichnete Kategorie NSAttributedString + CCLFormat für NSAttributedStrings zu verwenden, mit der Sie Folgendes schreiben können:

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

Es benutzt es natürlich nur NSMutableAttributedString unter der Decke verwendet.

Es hat auch den zusätzlichen Vorteil, dass es eine vollwertige Formatierungsfunktion ist - es kann also viel mehr als nur Zeichenfolgen anhängen.

Fatuhoku
quelle
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
quelle
1

Sie können SwiftyFormat ausprobieren . Es verwendet die folgende Syntax

let format = "#{{user}} mentioned you in a comment. #{{comment}}"
let message = NSAttributedString(format: format,
                                 attributes: commonAttributes,
                                 mapping: ["user": attributedName, "comment": attributedComment])
Igor Palaguta
quelle
1
Können Sie es bitte näher erläutern? Wie funktioniert sein Wille?
Kandhal Bhutiya