Reemplace la subcadena de NSAttributedString con otra NSAttributedString
cocoa replace (8)
Quiero reemplazar una subcadena (por ejemplo, @"replace"
) de un NSAttributedString
con otro NSAttributedString
.
Estoy buscando un método equivalente al NSString
de stringByReplacingOccurrencesOfString:withString:
para NSAttributedString
.
Convierta su cadena atribuida en una instancia de
NSMutableAttributedString
.La cadena atribuible mutable tiene una propiedad
mutableString
. De acuerdo con la documentación:"El receptor rastrea los cambios en esta cadena y mantiene sus asignaciones de atributos actualizadas".
De modo que puede usar la cadena mutable resultante para ejecutar el reemplazo con
replaceOccurrencesOfString:withString:options:range:
Aquí es cómo puede cambiar la cadena de NSMutableAttributedString, conservando sus atributos:
Rápido:
// 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")
C objetivo:
NSMutableAttributedString *newAttrStr = [attribtedTxt.mutableString setString:@"new string"];
Con Swift 4 y iOS 11, puede usar una de las 2 formas siguientes 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 de Playground a continuación muestra cómo usar replaceCharacters(in:with:)
con el fin de reemplazar una subcadena de una instancia de NSMutableAttributedString
con una nueva instancia de 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 el NSMutableString
replaceOccurrences(of:with:options:range:)
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 de Playground a continuación muestra cómo usar replaceOccurrences(of:with:options:range:)
para reemplazar una subcadena de una instancia de NSMutableAttributedString
con una nueva instancia de 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)
En mi caso, la siguiente manera fue la única (probado 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, sería bueno encontrar otra forma mejor.
Encuentro que todas las demás respuestas no funcionan. Aquí es cómo 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
}
Tengo un requisito específico y lo fijo como a continuación. Esto podría ayudar a alguien.
Requisito: en el guión 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 de info plist.
Solución: Se eliminó la versión número 1.0 del guión gráfico, solo se guardó la "Versión de la aplicación:" y se 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!! Actualizado / modificado attributeText.
Tuve que escribir texto en negrita en las etiquetas <b>
, aquí lo que hice:
- (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;
}
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];