Search code examples
iosswiftnsattributedstringnsrange

how to addAttributes to an array of strings?


I encountered a problem here. I would like to addAttributes to strings I collected from an array. How do I go about it from my incomplete function?

EDITED: the code works alright but just as @Larme said, by using range, the attribute text will only append to the first range found, not the rest. For example, if the text is Desmond is careless, I am <b>desmond<b> with a <b>car<b> the end result will be Desmond is careless, I am desmond with a car any idea how to find the range index with repeated append?

 func find(inText text: String, pattern: String) -> [String]?
    {
        let regex = try! NSRegularExpression(pattern:pattern+"(.*?)"+pattern, options: [])
        var results = [String]()

        regex.enumerateMatches(in: text, options: [], range: NSMakeRange(0, text.utf16.count))
        { result, flags, stop in
            if let r = result?.range(at: 1),
               let range = Range(r, in: text)
            {
                results.append(String(text[range]))
            }
        }
        return results
    }

   let colorAttribute =
        [NSAttributedStringKey.font: Fonts.OpenSansSemibold(isPhoneSE ? 13 :isPhone3 ? 12 : 16),
         NSAttributedStringKey.foregroundColor: Colors.slate] as [NSAttributedStringKey : Any]

    ***EDITED***

    let boldStrArray = find(inText: item.inbox_body, pattern: "<b>") // find the bold text

    let replaceStr = item.inbox_body!.replacingOccurrences(of: "<b>", with: "")

    print(boldStrArray) //["desmond", "car"]
    print(replaceStr)

    let attrStr = NSMutableAttributedString(string: replaceStr, attributes: normalAttribute)

    for b in boldStrArray!
    {
        let range = (replaceStr as! NSMutableString).range(of: b)
        print(range)
        attrStr.setAttributes(colorAttribute, range: range)
        //attrStr.addAttributes(colorAttribute, range: range)
    }

any comments are greatly appreciated :)


Solution

  • It'd be easier if find(inText:pattern:) returns (NS)Ranges (or assimilated even better NSTextCheckingResults).

    So with some modifications:

    func find(inText text: String, pattern: String) -> [NSTextCheckingResult] {
        let regex = try! NSRegularExpression(pattern:pattern+"(.*?)"+pattern, options: []) //There should be a try/catch at least
        return regex.matches(in: text, options: [], range: NSRange.init(location: 0, length: text.utf16.count))
    }
    

    I used my "own font & color", because I don't have your settings. Because it's not easily guessable that you can use the range(at: 1) depending on the pattern you use, I wouldn't use a method but write it inside it.

    let initialString = "I am <b>desmond<b> with a <b>car<b>"
    let colorAttribute: [NSAttributedStringKey : Any] = [.font: UIFont.boldSystemFont(ofSize: 12),
                                                         .foregroundColor: UIColor.red]
    
    var attrStr = NSMutableAttributedString(string: initialString)
    print("BEFORE attrStr: \(attrStr)")
    let boldRanges = find(inText: initialString, pattern: "<b>")
    boldRanges.reversed().forEach { (aResult) in
        let subTextNSRange = aResult.range(at: 1)
        guard let subTextRange = Range(subTextNSRange, in: attrStr.string) else { return } //This is to "switch" between NSRange & Range
        let replacementString = String(attrStr.string[subTextRange])
        let replacementAttributedString = NSAttributedString(string: replacementString, attributes: colorAttribute)
        attrStr.replaceCharacters(in: aResult.range, with: replacementAttributedString)
    }
    print("AFTER attrStr: \(attrStr)")
    

    Output:

    $> BEFORE attrStr: I am <b>desmond<b> with a <b>car<b>{
    }
    $> AFTER attrStr: I am {
    }desmond{
        NSColor = "sRGB IEC61966-2.1 colorspace 1 0 0 1";
        NSFont = "\".AppleSystemUIFontBold 12.00 pt. P [] (0x60c000051e50) fobj=0x101a36cf0, spc=3.09\"";
    } with a {
    }car{
        NSColor = "sRGB IEC61966-2.1 colorspace 1 0 0 1";
        NSFont = "\".AppleSystemUIFontBold 12.00 pt. P [] (0x60c000051e50) fobj=0x101a36cf0, spc=3.09\"";
    }