将 NSAttributedString 的子字符串替换为另一个 NSAttributedString

发布于 2024-12-17 14:56:45 字数 431 浏览 2 评论 0 原文

我想用另一个 NSAttributedString 替换 NSAttributedString 的子字符串(例如 @"replace")。

我正在寻找与 NSStringstringByReplacingOccurrencesOfString:withString:NSAttributedString

I want to replace a substring (e.g. @"replace") of an NSAttributedString with another NSAttributedString.

I am looking for an equivalent method to NSString's stringByReplacingOccurrencesOfString:withString: for NSAttributedString.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

一口甜 2024-12-24 14:56:45
  1. 将属性字符串转换为 NSMutableAttributedString 的实例。

  2. 可变属性字符串有一个 mutableString 属性。根据文档:

    <块引用>

    “接收器跟踪此字符串的更改并保持其属性映射最新。”

    因此,您可以使用生成的可变字符串来执行替换 replaceOccurrencesOfString:withString:options:range:

  1. Convert your attributed string into an instance of NSMutableAttributedString.

  2. The mutable attributed string has a mutableString property. According to the documentation:

    "The receiver tracks changes to this string and keeps its attribute mappings up to date."

    So you can use the resulting mutable string to execute the replacement with replaceOccurrencesOfString:withString:options:range:.

戏剧牡丹亭 2024-12-24 14:56:45

就我而言,以下方法是唯一的(在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];
    }

当然,找到另一种更好的方法会很高兴。

In my case, the following way was the only (tested on 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];
    }

Of course it will be nice to find another better way.

月下伊人醉 2024-12-24 14:56:45

以下是如何更改 NSMutableAttributedString 的字符串,同时保留其属性:

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")

Objective-C:

NSMutableAttributedString *newAttrStr = [attribtedTxt.mutableString setString:@"new string"];

Here is how you can change the string of NSMutableAttributedString, while preserving its attributes:

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")

Objective-C:

NSMutableAttributedString *newAttrStr = [attribtedTxt.mutableString setString:@"new string"];
凝望流年 2024-12-24 14:56:45

斯威夫特4:
更新了 Swift 4 的 sunkas 优秀解决方案,并封装在“扩展”中。只需将其夹入 ViewController(在类之外)并使用它即可。

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
    }
}

Swift 4:
Updated sunkas excellent solution to Swift 4 and wrapped in "extension". Just clip this into your ViewController (outside the class) and use it.

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
    }
}
旧人哭 2024-12-24 14:56:45

对于 Swift 4 和 iOS 11,您可以使用以下 2 种方法之一来解决您的问题。


#1.使用 NSMutableAttributedString replaceCharacters(in:with:) 方法

NSMutableAttributedString 有一个名为 replaceCharacters(in:with:)replaceCharacters(in:with:) 具有以下声明:

用给定属性字符串的字符和属性替换给定范围内的字符和属性。

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

下面的 Playground 代码展示了如何使用 replaceCharacters(in:with:)NSMutableAttributedString 实例的子字符串替换为新的 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。使用 NSMutableString replaceOccurrences(of:with:options:range:) 方法

NSMutableString 有一个名为 replaceOccurrences(of:with:options:range:)replaceOccurrences(of:with:options:range:) 具有以下声明:

用另一个给定字符串替换给定范围内所有出现的给定字符串,并返回替换次数。

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

下面的 Playground 代码展示了如何使用 replaceOccurrences(of:with:options:range:)NSMutableAttributedString 实例的子字符串替换为新的 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)

With Swift 4 and iOS 11, you can use one of the 2 following ways in order to solve your problem.


#1. Using NSMutableAttributedString replaceCharacters(in:with:) method

NSMutableAttributedString has a method called replaceCharacters(in:with:). replaceCharacters(in:with:) has the following declaration:

Replaces the characters and attributes in a given range with the characters and attributes of the given attributed string.

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

The Playground code below shows how to use replaceCharacters(in:with:) in order to replace a substring of an NSMutableAttributedString instance with a new NSMutableAttributedString instance:

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. Using NSMutableString replaceOccurrences(of:with:options:range:) method

NSMutableString has a method called replaceOccurrences(of:with:options:range:). replaceOccurrences(of:with:options:range:) has the following declaration:

Replaces all occurrences of a given string in a given range with another given string, returning the number of replacements.

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

The Playground code below shows how to use replaceOccurrences(of:with:options:range:) in order to replace a substring of an NSMutableAttributedString instance with a new NSMutableAttributedString instance:

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)
征﹌骨岁月お 2024-12-24 14:56:45

我必须将 标记中的文本加粗,这是我所做的:

- (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;
}

I had to bold text in <b> tags, here what I've done:

- (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;
}
花开半夏魅人心 2024-12-24 14:56:45
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];
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];
窗影残 2024-12-24 14:56:45

我发现所有其他答案都不起作用。以下是我在类别扩展中替换 NSAttributed 字符串内容的方法:

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
}

I find that all of the other answers does not work. Here is how I replaced content of a NSAttributed string in a category extension:

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
}
汐鸠 2024-12-24 14:56:45

我有一个特定的要求并固定如下。这可能会对某人有所帮助。

需求:在storyboard中,直接在UITextView的属性中添加富文本,其中包含“App Version: 1.0”一词。现在我必须通过从 info plist 读取版本号来动态化版本号。

解决方案:
从故事板中删除了版本号 1.0,只保留“应用程序版本:”并添加以下代码。

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

完毕!!更新/修改了属性文本。

I have a specific requirement and fixed like below. This might help someone.

Requirement: In the storyboard, rich text directly added to UITextView's attribute which contains a word "App Version: 1.0". Now I have to dynamise the version number by reading it from info plist.

Solution:
Deleted version number 1.0 from the storyboard, just kept "App Version:" and added below code.

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

Done!! Updated/modified attributedText.

瑾夏年华 2024-12-24 14:56:45

我为该

extension NSAttributedString {
    
    func replacingOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString {
        
        let s = NSMutableAttributedString(attributedString: self)
        s.beginEditing()
        s.replaceOccurrences(of: target, with: replacement, attributes: attributes)
        s.endEditing()
        return s
        
    }
    
}

extension NSMutableAttributedString {

    func replaceOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) {
        
        var searchRange = NSRange(location: 0, length: self.length)
        
        while let range = self.string.range(of: target, options: [], range: Range(searchRange, in: self.string)) {
            let nsRange = NSRange(range, in: self.string)
            self.replaceCharacters(in: nsRange, with: replacement)
            
            let newRange = NSRange(location: nsRange.location, length: replacement.count)
            if let attributes = attributes {
                self.addAttributes(attributes, range: newRange)
            }
            
            searchRange = NSRange(location: newRange.upperBound, length: self.length - newRange.upperBound)
        }
        
    }
    
}

用例创建了一个 Swift 5 扩展

attributedString.replacingOccurrences(of: "%EMAIL%", with: email, attributes: [.font:boldFont])
        

i created a Swift 5 extension for that

extension NSAttributedString {
    
    func replacingOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString {
        
        let s = NSMutableAttributedString(attributedString: self)
        s.beginEditing()
        s.replaceOccurrences(of: target, with: replacement, attributes: attributes)
        s.endEditing()
        return s
        
    }
    
}

extension NSMutableAttributedString {

    func replaceOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) {
        
        var searchRange = NSRange(location: 0, length: self.length)
        
        while let range = self.string.range(of: target, options: [], range: Range(searchRange, in: self.string)) {
            let nsRange = NSRange(range, in: self.string)
            self.replaceCharacters(in: nsRange, with: replacement)
            
            let newRange = NSRange(location: nsRange.location, length: replacement.count)
            if let attributes = attributes {
                self.addAttributes(attributes, range: newRange)
            }
            
            searchRange = NSRange(location: newRange.upperBound, length: self.length - newRange.upperBound)
        }
        
    }
    
}

use case

attributedString.replacingOccurrences(of: "%EMAIL%", with: email, attributes: [.font:boldFont])
        
此刻的回忆 2024-12-24 14:56:45

完整的解决方案

extension NSAttributedString {
    
    func replacingOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString {
        
        let s = NSMutableAttributedString(attributedString: self)
        s.beginEditing()
        s.replaceOccurrences(of: target, with: replacement, attributes: attributes)
        s.endEditing()
        return s
        
    }
    
}

extension NSMutableAttributedString {

    func replaceOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) {
        
        var searchRange = NSRange(location: 0, length: self.length)
        
        while let range = self.string.range(of: target, options: [], range: Range(searchRange, in: self.string)) {
            let nsRange = NSRange(range, in: self.string)
            self.replaceCharacters(in: nsRange, with: replacement)
            
            let newRange = NSRange(location: nsRange.location, length: replacement.count)
            if let attributes = attributes {
                self.addAttributes(attributes, range: newRange)
            }
            
            searchRange = NSRange(location: newRange.upperBound, length: self.length - newRange.upperBound)
        }
        
    }
    
}

the full solution

extension NSAttributedString {
    
    func replacingOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString {
        
        let s = NSMutableAttributedString(attributedString: self)
        s.beginEditing()
        s.replaceOccurrences(of: target, with: replacement, attributes: attributes)
        s.endEditing()
        return s
        
    }
    
}

extension NSMutableAttributedString {

    func replaceOccurrences(of target: String, with replacement: String, attributes: [NSAttributedString.Key : Any]? = nil) {
        
        var searchRange = NSRange(location: 0, length: self.length)
        
        while let range = self.string.range(of: target, options: [], range: Range(searchRange, in: self.string)) {
            let nsRange = NSRange(range, in: self.string)
            self.replaceCharacters(in: nsRange, with: replacement)
            
            let newRange = NSRange(location: nsRange.location, length: replacement.count)
            if let attributes = attributes {
                self.addAttributes(attributes, range: newRange)
            }
            
            searchRange = NSRange(location: newRange.upperBound, length: self.length - newRange.upperBound)
        }
        
    }
    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文