0
func testFunc(attribString: AttributedString)->AttributedString {

    // attribString is a markdown AttributedString for example = "Lorem ipsum dolor <test>first tag</test>sit Donec <test>second tag</test>"

    if let range = attribString.range(of: "<test>(.*?)</test>", options: .regularExpression) {

        attribString[range].foregroundColor = .red
        
    }
}

the documentation says: range(of) - Finds and returns the range of the first occurrence of a given string within the string.

But how can I find the range of all occurrences in the string with regex so that I can assign it a color or other attribute?

Could a loop be a good idea?

for range in ranges {
     attribString[range].foregroundColor = .red
}

Thanks for help

Willeke
  • 14,578
  • 4
  • 19
  • 47
Stefano Vet
  • 567
  • 1
  • 7
  • 18
  • You can use a `NSRegularExpression`. Also, you don't remove the tag `` & `` afterwards? – Larme Jul 27 '22 at 20:26
  • for use NSRegularExpression and than enumerateMatches i need a string ... regex.enumerateMatches(in: attribString .... but attribString is an AttributeString ... thanks – Stefano Vet Jul 27 '22 at 20:53
  • Indeed. You could use `NSAttributedString` (since you can go `NSAttributedString` <-> `AttributedString`), and do it on that `NSMutableAttributedString` (mutable, since you modify it). – Larme Jul 27 '22 at 20:59
  • Or use a while/recursive loop: If you find a range, add the effect, then, break the AttributedString, from end of found range to end of it, and redo the `range(of:options:)` on the rest, etc. – Larme Jul 27 '22 at 21:00
  • have a look at this SO post "...To find all substrings that are between a starting string and an ending string." :https://stackoverflow.com/questions/31725424/swift-get-string-between-2-strings-in-a-string look for `sliceMultipleTimes` – workingdog support Ukraine Jul 27 '22 at 23:10
  • I have some test code that may provide a solution, but I'm not sure what you want. Do you want to "paint" the `first tag` etc... red? Do you want to keep the "markers", `` and ``, or you want them removed from the final attributed string and only have the `first tag` etc... red? – workingdog support Ukraine Jul 28 '22 at 03:22
  • @workingdogsupportUkraine exactly. For me it is enough to keep the tags and color the whole block red. Range (of) is right, the only thing is to be able to do the same action on all selections in the text. Thank you! – Stefano Vet Jul 28 '22 at 06:11

1 Answers1

1

here is a possible solution to achieve ...to keep the <test> </test> tags and color the whole block red... (adjust the code according to your needs). It does not involve regex, it is based on the code (sliceMultipleTimes) at: Swift Get string between 2 strings in a string

struct ContentView: View {
    @State var attStr: AttributedString?
    
    var body: some View {
        Text(attStr ?? "nothing")
            .onAppear {
                let str = "Lorem ipsum dolor <test>first tag</test> sit Donec <test>second tag</test>"
                attStr = transform(str, from: "<test>", to: "</test>", with: .red)
            }
    }

    func transform(_ input: String, from: String, to: String, with color: Color) -> AttributedString {
        var attInput = AttributedString(input)
        let _ = input.components(separatedBy: from).compactMap { sub in
            (sub.range(of: to)?.lowerBound).flatMap { endRange in
                let s = String(sub[sub.startIndex ..< endRange])
                // use `s` for just the middle string
                if let theRange = attInput.range(of: (from + s + to)) {
                    attInput[theRange].foregroundColor = color
                }
            }
        }
        return attInput
    }
}