Reemplazar la subcadena de NSAttributedString con otra NSAttributedString


Quiero reemplazar una subcadena (por ejemplo, @"replace") de un NSAttributedString con otro NSAttributedString.

Estoy buscando un método equivalente a NSString's stringByReplacingOccurrencesOfString:withString: para NSAttributedString.

Author: Demitri, 2011-11-22

9 answers

  1. Convierta su cadena atribuida en una instancia de NSMutableAttributedString.

  2. La cadena atribuida mutable tiene una propiedad mutableString. Según la documentación:

    "El receptor rastrea los cambios en esta cadena y mantiene sus asignaciones de atributos actualizadas."

    Así que puede usar la cadena mutable resultante para ejecutar el reemplazo con replaceOccurrencesOfString:withString:options:range:.

 70
Author: Ole Begemann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-27 10:32:47

Así es como puedes cambiar la cadena de NSMutableAttributedString, mientras conservas sus atributos:

Swift:

// first we create a mutable copy of attributed text 
let originalAttributedText = nameLabel.attributedText?.mutableCopy() as! NSMutableAttributedString

// then we replace text so easily
let newAttributedText = originalAttributedText.mutableString.setString("new text to replace")

Objetivo-C:

NSMutableAttributedString *newAttrStr = [attribtedTxt.mutableString setString:@"new string"];
 19
Author: Hashem Aboonajmi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-12 10:07:20

En mi caso, la siguiente manera fue la única (probada en iOS9):

NSAttributedString *attributedString = ...;
NSAttributedString *anotherAttributedString = ...; //the string which will replace

while ([attributedString.mutableString containsString:@"replace"]) {
        NSRange range = [attributedString.mutableString rangeOfString:@"replace"];
        [attributedString replaceCharactersInRange:range  withAttributedString:anotherAttributedString];
    }

Por supuesto que será bueno encontrar otra manera mejor.

 16
Author: Darius Miliauskas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-25 08:30:04

Con Swift 4 e iOS 11, puede usar una de las 2 siguientes formas para resolver su problema.


#1. Usando NSMutableAttributedString replaceCharacters(in:with:) método

NSMutableAttributedString tiene un método llamado replaceCharacters(in:with:). replaceCharacters(in:with:) tiene la siguiente declaración:

Reemplaza los caracteres y atributos en un rango dado con los caracteres y atributos de la cadena atribuida dada.

func replaceCharacters(in range: NSRange, with attrString: NSAttributedString)

El código del patio de recreo a continuación muestra cómo usar replaceCharacters(in:with:) para reemplazar una subcadena de una instancia NSMutableAttributedString con una nueva instancia NSMutableAttributedString:

import UIKit

// Set initial attributed string
let initialString = "This is the initial string"
let attributes = [NSAttributedStringKey.foregroundColor : UIColor.red]
let mutableAttributedString = NSMutableAttributedString(string: initialString, attributes: attributes)

// Set new attributed string
let newString = "new"
let newAttributes = [NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue]
let newAttributedString = NSMutableAttributedString(string: newString, attributes: newAttributes)

// Get range of text to replace
guard let range = mutableAttributedString.string.range(of: "initial") else { exit(0) }
let nsRange = NSRange(range, in: mutableAttributedString.string)

// Replace content in range with the new content
mutableAttributedString.replaceCharacters(in: nsRange, with: newAttributedString)

#2. Usando NSMutableString replaceOccurrences(of:with:options:range:) método

NSMutableString tiene un método llamado replaceOccurrences(of:with:options:range:). replaceOccurrences(of:with:options:range:) tiene la siguiente declaración:

Reemplaza todas las ocurrencias de una cadena dada en un rango dado con otra cadena dada, devolviendo el número de reemplazos.

func replaceOccurrences(of target: String, with replacement: String, options: NSString.CompareOptions = [], range searchRange: NSRange) -> Int

El código del patio de recreo a continuación muestra cómo usar replaceOccurrences(of:with:options:range:) para reemplazar una subcadena de un NSMutableAttributedString instancia con una nueva instancia NSMutableAttributedString:

import UIKit

// Set initial attributed string
let initialString = "This is the initial string"
let attributes = [NSAttributedStringKey.foregroundColor : UIColor.red]
let mutableAttributedString = NSMutableAttributedString(string: initialString, attributes: attributes)

// Set new string
let newString = "new"

// Replace replaceable content in mutableAttributedString with new content
let totalRange = NSRange(location: 0, length: mutableAttributedString.string.count)
_ = mutableAttributedString.mutableString.replaceOccurrences(of: "initial", with: newString, options: [], range: totalRange)

// Get range of text that requires new attributes
guard let range = mutableAttributedString.string.range(of: newString) else { exit(0) }
let nsRange = NSRange(range, in: mutableAttributedString.string)

// Apply new attributes to the text matching the range
let newAttributes = [NSAttributedStringKey.underlineStyle : NSUnderlineStyle.styleSingle.rawValue]
mutableAttributedString.setAttributes(newAttributes, range: nsRange)
 8
Author: Imanou Petit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-21 13:13:41

Tuve que negrita texto en <b> etiquetas, aquí lo que he hecho:

- (NSAttributedString *)boldString:(NSString *)string {
    UIFont *boldFont = [UIFont boldSystemFontOfSize:14];
    NSMutableAttributedString *attributedDescription = [[NSMutableAttributedString alloc] initWithString:string];

    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@".*?<b>(.*?)<\\/b>.*?" options:NSRegularExpressionCaseInsensitive error:NULL];
    NSArray *myArray = [regex matchesInString:string options:0 range:NSMakeRange(0, string.length)] ;
    for (NSTextCheckingResult *match in myArray) {
        NSRange matchRange = [match rangeAtIndex:1];
        [attributedDescription addAttribute:NSFontAttributeName value:boldFont range:matchRange];
    }
    while ([attributedDescription.string containsString:@"<b>"] || [attributedDescription.string containsString:@"</b>"]) {
        NSRange rangeOfTag = [attributedDescription.string rangeOfString:@"<b>"];
        [attributedDescription replaceCharactersInRange:rangeOfTag withString:@""];
        rangeOfTag = [attributedDescription.string rangeOfString:@"</b>"];
        [attributedDescription replaceCharactersInRange:rangeOfTag withString:@""];
    }
    return attributedDescription;
}
 5
Author: trickster77777,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-24 12:58:21
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] initWithString:@"I am a boy."];
[result addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, [result length])];

NSMutableAttributedString *replace = [[NSMutableAttributedString alloc] initWithString:@"a"];
[replace addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, [replace length])];

[result replaceCharactersInRange:NSMakeRange(5, [replace length]) withAttributedString:replace];
 3
Author: Chan Kai Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-12 11:15:11

Encuentro que todas las otras respuestas no funcionan. Así es como reemplacé el contenido de una cadena NSAttributed en una extensión de categoría:

func stringWithString(stringToReplace:String, replacedWithString newStringPart:String) -> NSMutableAttributedString
{
    let mutableAttributedString = mutableCopy() as! NSMutableAttributedString
    let mutableString = mutableAttributedString.mutableString

    while mutableString.containsString(stringToReplace) {
        let rangeOfStringToBeReplaced = mutableString.rangeOfString(stringToReplace)
        mutableAttributedString.replaceCharactersInRange(rangeOfStringToBeReplaced, withString: newStringPart)
    }
    return mutableAttributedString
}
 2
Author: Sunkas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-31 10:09:56

Swift 4: Actualizado sunkas excelente solución para Swift 4 y envuelto en "extensión". Simplemente recorte esto en su ViewController (fuera de la clase) y úselo.

extension NSAttributedString {
    func stringWithString(stringToReplace: String, replacedWithString newStringPart: String) -> NSMutableAttributedString
    {
        let mutableAttributedString = mutableCopy() as! NSMutableAttributedString
        let mutableString = mutableAttributedString.mutableString
        while mutableString.contains(stringToReplace) {
            let rangeOfStringToBeReplaced = mutableString.range(of: stringToReplace)
            mutableAttributedString.replaceCharacters(in: rangeOfStringToBeReplaced, with: newStringPart)
        }
        return mutableAttributedString
    }
}
 2
Author: gundrabur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-04 07:37:54

Tengo un requisito específico y fijo como a continuación. Esto podría ayudar a alguien.

Requisito: En el guion gráfico, el texto enriquecido se agrega directamente al atributo UITextView que contiene una palabra "Versión de la aplicación: 1.0". Ahora tengo que dinamizar el número de versión leyéndolo desde info plist.

Solución: El número de versión eliminado 1.0 del guion gráfico, solo mantuvo "Versión de la aplicación:" y agregó el código siguiente.

NSAttributedString *attribute = self.firsttextView.attributedText;
NSMutableAttributedString *mutableAttri = [[NSMutableAttributedString alloc] initWithAttributedString:attribute];
NSString *appVersionText = @"App Version:";
if ([[mutableAttri mutableString] containsString:appVersionText]) {
    NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
    NSString* version = [infoDict objectForKey:@"CFBundleShortVersionString"];
    NSString *newappversion = [NSString stringWithFormat:@"%@ %@",appVersionText,version] ;
    [[mutableAttri mutableString] replaceOccurrencesOfString:appVersionText withString:newappversion options:NSCaseInsensitiveSearch range:NSMakeRange(0, mutableAttri.length)];
    self.firsttextView.attributedText = mutableAttri;
}

Hecho!! Texto atribuido actualizado / modificado.

 0
Author: Suresh Durishetti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-27 07:26:04