0

I have a UILabel with text "hello world, hello". There are 2 hello words. And I want to replace the only 'bold hello' to 'thanks' without bold.

I use this code:

uiLabel1.text = "hello world, hello"

let target = "hello"

let replace = "thanks"

uiLabel1.text.replacingOccurrences(of: target, with: replace, options: NSString.CompareOptions.literal, range: nil)

And the result is: "thanks world, thanks"
The result I want: "hello world, thanks"

Imanuel Pardosi
  • 311
  • 1
  • 5
  • 13
  • You are just searching and replacing a word, so the code does that I would expect. You need to check the string attributes of each word to determine which hello is bold, your code doesn't do enough to match your requirements currently. – Scriptable Aug 08 '18 at 08:49
  • 1
    `"hello world, hello".replacingOccurrences(of: "hello", with: "thanks")`? – MadProgrammer Aug 08 '18 at 09:01
  • Hi @MadProgrammer, my bad, there is wrong with my code there is no tag . I already updated the code above. – Imanuel Pardosi Aug 08 '18 at 10:04
  • @ImanuelPardosi It's not exactly a single liner, but I've posted one way to do it – MadProgrammer Aug 08 '18 at 10:17

2 Answers2

2

Okay, so there's probably an easier way to do this...

So, I went through the API (like super quick) and looked for something like lastIndexOf, which lead me on a little trail to String#range(of:options), which allows you to search backwards, hmmm, interesting.

This returns a Range<String.Index> ... okay, so how can I use that?! Hmm, maybe String#replacingOccurrences(of:with:options:range:)

So, crack open a play ground and...

var str = "hello world, hello"
let lastIndexOf = str.range(of: "hello", options: .backwards)
str = str.replacingOccurrences(of: "hello", with: "thanks", options: .caseInsensitive, range: lastIndexOf)

str now equals "hello world, thanks"

Hi @MadProgrammer, your code is to replace the last hello word to thanks, right? But my question is to replace hello with the bold attribute, it may in the first, middle or at the end of a string.

Okay, so clearly we're missing some context...

Assuming, now, you're using a NSAttributedString, it becomes slightly more complicated

Building the string itself is not hard, figuring out how to find string components by attribute, a little more difficult.

Lucky for us, we have the Internet. So, the following is based on ideas I got from:

One of the important things to remember when trying to solve an issue, you'll be lucky to find a single answer which does it all, instead, you need to break your issue down and focus on solving individual elements, and be prepared to go back to the start

So, once again, unto the play ground...

import UIKit

var str = "hello world, "
//let lastIndexOf = str.range(of: "hello", options: .backwards)
//str = str.replacingOccurrences(of: "hello", with: "thanks", options: .caseInsensitive, range: lastIndexOf)

extension UIFont {
    var isBold: Bool {
        return fontDescriptor.symbolicTraits.contains(.traitBold)
    }

    var isItalic: Bool {
        return fontDescriptor.symbolicTraits.contains(.traitItalic)
    }
}

// Just so I can see that the style ;)    
let fontSize = CGFloat(24.0)
let boldAttrs = [
    NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: fontSize),
    NSAttributedString.Key.foregroundColor: UIColor.white // Playground
]
// Playground only
let plainAttrs = [
    NSAttributedString.Key.foregroundColor: UIColor.white // Playground
]

let boldText = NSMutableAttributedString(string: "hello", attributes: boldAttrs)
let styledText = NSMutableAttributedString(string: str, attributes: plainAttrs)
let someMoreBoldText = NSMutableAttributedString(string: "not to be replaced", attributes: boldAttrs)

// Attributes can be combined with their appear together ;)
styledText.append(boldText)
styledText.append(NSMutableAttributedString(string: " ", attributes: plainAttrs))
styledText.append(someMoreBoldText)
styledText.append(NSMutableAttributedString(string: " ", attributes: plainAttrs))
styledText.append(boldText)

styledText.enumerateAttribute(NSAttributedString.Key.font, in: NSRange(0..<styledText.length)) { (value, range, stop) in
    guard let font = value as? UIFont, font.isBold else {
        return;
    }
    let subText = styledText.attributedSubstring(from: range)
    guard subText.string == "hello" else {
        return
    }
    styledText.replaceCharacters(in: range, with: "thanks")
}
styledText

Which outputs...

Output

The important things for me are:

  1. The style has not be changed
  2. Only the individual "hello" values, which are bolded, have been changed
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Hi @MadProgrammer, your code is to replace the last hello word to thanks, right? But my question is to replace hello with the bold attribute, it may in the first, middle or at the end of a string. – Imanuel Pardosi Aug 08 '18 at 15:30
  • Then you’re using a NSAttributedString then? Because that’s the only way I know you could have a bold attribute – MadProgrammer Aug 08 '18 at 19:44
0

Here is the code. But actually this is hardcoded. If the target enclosed in between <b></b>, it will work.

var text = "hello world, <b>hello</b>"
let target = "hello"
let replace = "thanks"

text = text.replacingOccurrences(of: "<b>\(target)</b>", with: replace, options: .literal, range: nil) //hello world, thanks
Lal Krishna
  • 15,485
  • 6
  • 64
  • 84