-3

I have a string in the form of

"@{profile: id1} is going to @{profile: id2}'s party"

How do I convert it to nsattributedstring

"**Name1** is going to **Name2**'s party"

Both id1 and id2 represent a string. You can get Name1 by pass id1 into a function named getName(by id: String)

Given a string

"@{profile: 735bcec0-1470-11e9-8384-a57f51e70e5f} is \
going to @{profile: 4c0bf620-2022-11e9-99ad-0777e9298bfb} party."

Assume

getName(by: "735bcec0-1470-11e9-8384-a57f51e70e5f") -> "Jack"
getName(by: "4c0bf620-2022-11e9-99ad-0777e9298bfb") -> "Rose"

I would like to get back a nsattributedstring

"Jack is going to Rose's party"

Where both Jack and Rose should be bold.

Zion W
  • 15
  • 6
  • Not able to understand your question completely. – Shivam Pokhriyal Jan 25 '19 at 19:25
  • 2
    Too much depends on what exactly you need to do. Is this a one-shot replacement of what looks like one Objc-C String to a Swift string? Use simple replacements, like"@{" to "\(" and "profile: " to "profile_". Do you need this for more complex expressions and substrings? Then regular expression might be more suitable. Even more complex scenarios? Then a real tokenizer/parser might be needed. – Gereon Jan 25 '19 at 19:25

1 Answers1

0

You can use regex in addition to replaceCharacters(in:with:) method of NSMutableAttributedString:

    //Prepare attributes for Normal and Bold
    let normalAttr: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 24.0)
    ]
    let boldAttr: [NSAttributedString.Key: Any] = [
        .font: UIFont.boldSystemFont(ofSize: 24.0)
    ]
    //Create an NSMutableAttributedString from your given string
    let givenString = """
    @{profile: 735bcec0-1470-11e9-8384-a57f51e70e5f} is \
    going to @{profile: 4c0bf620-2022-11e9-99ad-0777e9298bfb}'s party.
    """
    let attrString = NSMutableAttributedString(string: givenString, attributes: normalAttr)
    //Create a regex matching @{profile: id} with capturing id
    let pattern = "@\\{profile:\\s*([^}]+)\\}"
    let regex = try! NSRegularExpression(pattern: pattern, options: [])
    let matches = regex.matches(in: givenString, range: NSRange(0..<givenString.utf16.count))
    //Iterate on matches in reversed order (to keep NSRanges consistent)
    for match in matches.reversed() {
        //Retrieve id from the first captured range
        let idRange = Range(match.range(at: 1), in: givenString)!
        let id = String(givenString[idRange])
        let name = getName(by: id)
        //Convert it to an NSAttributedString with bold attribute
        let boldName = NSAttributedString(string: name, attributes: boldAttr)
        //Replace the matching range with the bold name
        attrString.replaceCharacters(in: match.range, with: boldName)
    }
OOPer
  • 47,149
  • 6
  • 107
  • 142
  • Thanks for your help. It worked fine for the first match to be replaced. But the second replacement failed. I guess it's because the first replacement changed attrString, so the range won't match when the second replacement happened. – Zion W Jan 26 '19 at 21:07
  • ```Terminating app due to uncaught exception 'NSRangeException', reason: 'NSMutableRLEArray replaceObjectsInRange:withObject:length:: Out of bounds'``` This is the error I got when the app crashed. – Zion W Jan 26 '19 at 21:07
  • Sorry, I missed your `reversed()` part. I figured it myself soon before I found that your solution is perfectly right. – Zion W Jan 26 '19 at 21:08