Как я могу объединить NSAttributedStrings?

159

Мне нужно найти несколько строк и установить некоторые атрибуты до слияния строк, поэтому наличие NSStrings -> Объединить их -> Сделать NSAttributedString не вариант, есть ли способ объединить attribuString с другой attribuString?

Imanou Petit
источник
13
Смешно, как трудно это все еще происходит в августе 2016 года.
Клин Мартин,
17
Даже в 2018 году ...
DehMotth
11
еще в 2019 году;)
raistlin
8
все еще в 2020 году ...
Хванхо Ким

Ответы:

210

Я бы порекомендовал вам использовать одну изменяемую атрибутивную строку, предложенную @Linuxios, и вот еще один пример этого:

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

Однако просто для того, чтобы получить все опции, вы также можете создать одну изменяемую атрибутивную строку, сделанную из отформатированной строки NSString, содержащей входные строки, уже собранные вместе. Затем вы можете использовать addAttributes: range:для добавления атрибутов после факта в диапазоны, содержащие входные строки. Я рекомендую первый способ, хотя.

Мик МакКаллум
источник
Почему вы рекомендуете добавлять строки вместо добавления атрибутов?
ma11hew28
87

Если вы используете Swift, вы можете просто перегрузить +оператор, чтобы объединить их так же, как и обычные строки:

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

Теперь вы можете объединить их, просто добавив:

let helloworld = NSAttributedString(string: "Hello ") + NSAttributedString(string: "World")
водорослевые
источник
5
изменяемый класс является подтипом неизменяемого класса.
Водоросль
4
Вы можете использовать изменяемый подтип в любом контексте, который ожидает неизменный родительский тип, но не наоборот. Вы можете рассмотреть подклассы и наследование.
Водоросль
6
Да, вы должны сделать защитную копию, если вы хотите быть в обороне. (Не сарказм.)
Водоросль
1
Если вы действительно хотите вернуть NSAttributedString, то, возможно, это сработает:return NSAttributedString(attributedString: result)
Alex
2
@ n13 Я бы создал папку с именем Helpersor Extensionsи поместил бы эту функцию в файл с именем NSAttributedString+Concatenate.swift.
Дэвид Лоусон
34

Swift 3: просто создайте NSMutableAttributedString и добавьте к ним приписанные строки.

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
    ]
Джош О'Коннор
источник
25

Попробуй это:

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

Где astring1и astring2есть NSAttributedStringс.

Linuxios
источник
13
Или [[aString1 mutableCopy] appendAttributedString: aString2].
JWWalker
@JWWalker ваш 'oneliner' поврежден. Вы не можете получить этот результат "конкатенации", потому что appendAttributedString не возвращает строку. Та же история со словарями
gaussblurinc
@gaussblurinc: хорошая мысль, конечно, ваша критика относится и к ответу, который мы комментируем. Так и должно быть NSMutableAttributedString* aString3 = [aString1 mutableCopy]; [aString3 appendAttributedString: aString2];.
JWWalker
@gaussblurinc, JWalker: исправил ответ.
Linuxios
@Linuxios, вы также вернетесь resultкак NSMutableAttributedString. это не то, что автор хочет видеть. stringByAppendingString- этот метод будет хорош
gaussblurinc
5

2020 | SWIFT 5.1:

Вы можете добавить 2 NSMutableAttributedStringследующим образом:

let concatenated = NSAttrStr1.append(NSAttrStr2)

Другой способ работает с NSMutableAttributedStringи NSAttributedStringоба:

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

Другой способ это ....

var full = NSAttrStr1 + NSAttrStr2 + NSAttrStr3

и:

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


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

Вы можете сделать это со следующим расширением:

// 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
    }
}
Андрей
источник
2
Я использую Swift 5.1 и я не могу просто добавить две NSAttrStrings вместе ...
PaulDoesDev
1
Странный. В этом случае просто используйтеNSAttrStr1.append(NSAttrStr2)
Андрей
Обновил мой ответ, добавив расширения для простого добавления двух NSAttrStrings :)
Андрей
4

Если вы используете Cocoapods, альтернатива обоим вышеприведенным ответам, позволяющая избежать изменчивости в вашем собственном коде, заключается в использовании превосходной категории NSAttributedString + CCLFormat для NSAttributedStrings, которая позволяет написать что-то вроде:

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

Это, конечно, он просто использует NSMutableAttributedStringпод одеялом.

Он также обладает дополнительным преимуществом, будучи полноценной функцией форматирования, так что он может сделать гораздо больше, чем просто добавлять строки вместе.

fatuhoku
источник
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
источник
1

Вы можете попробовать SwiftyFormat. Он использует следующий синтаксис

let format = "#{{user}} mentioned you in a comment. #{{comment}}"
let message = NSAttributedString(format: format,
                                 attributes: commonAttributes,
                                 mapping: ["user": attributedName, "comment": attributedComment])
Игорь Палагута
источник
1
Можете ли вы уточнить это подробнее? Как это будет работать?
Кандал Бхутия