1

I am styling some dynamic markdown, however the framework I am using for styling doesnt support nested tags for links.

I need to parse the string and close the styling markdown tags effectively this :

    "__Some bold text [FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\"), more bold text.__\n\n additional text \n\n
 *some italic text[SECOND LINK](https://SECONDLINK.COM) ending text,*"

to this:

    "__Some bold text __[FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\")__, more bold text.__\n\n additional text \n\n
 *some italic text*[SECOND LINK](https://SECONDLINK.COM)* ending text,*"

This is only really going to be for bold and italic text. I started going down the route of

var str = "__Some bold text [FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\"), more bold text.__\n\n additional text \n\n *some italic text[SECOND LINK](https://SECONDLINK.COM) ending text,*"

    let bold = str.components(separatedBy: "__")
    for var string in bold {
        if let matchedIndex = string.index(of: "[") {
            string.insert(contentsOf: "__", at: matchedIndex)
        }
    }

But wondered, is there a better way to do this in Swift?

Edit - for clarity - essentially I need to modify the existing string to have closed tags prior to a link tag and re opened after a link tag - this prevents the links from being nested with the style tags and allows the styler framework to apply attributed strings accordingly

EDIT --- in line with @Linus comment here is the results of the regex (note running these out side of an extension in order to be able to test in a playground

var str = "__Some bold text [FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\"), more bold text.__\n additional text \n *some italic text[SECOND LINK](https://SECONDLINK.COM) ending text,*\n__sfdadhfjkh [THIRD LINK](https://THIRDLINK.COM \"THIRD LINK\"), more bold text.__"

do {
    var regex = try NSRegularExpression(pattern:  "(\\[.*?\\))" , options: [.caseInsensitive])
    var newString = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.utf16.count), withTemplate: "__$1__")
    print("\nFirst regex  __$1__  \n\n\(newString)")

    regex = try NSRegularExpression(pattern:  "(\\[.*?\\))" , options: [.caseInsensitive])
        var newerString = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.utf16.count), withTemplate: "*$1*")
        print("\nSecond Regex *$1* \n\n"+newerString)
} catch { print("ERROR: searchFor regex (\("(\\[.*?\\))")) on string (\(str)) failed") }

Printed results

First regex  __$1__  

__Some bold text __[FIRST LINK](https://FIRSTLINK.COM "FIRST LINK")__, more bold text.__
 additional text 
 *some italic text__[SECOND LINK](https://SECONDLINK.COM)__ ending text,*
__sfdadhfjkh __[THIRD LINK](https://THIRDLINK.COM "THIRD LINK")__, more bold text.__

Second Regex *$1* 

__Some bold text *[FIRST LINK](https://FIRSTLINK.COM "FIRST LINK")*, more bold text.__
 additional text 
 *some italic text*[SECOND LINK](https://SECONDLINK.COM)* ending text,*
__sfdadhfjkh *[THIRD LINK](https://THIRDLINK.COM "THIRD LINK")*, more bold text.__

I need to have both Italic and strong tags amended on the same string in order to pass it to a view to be styled

3
  • Looks like a job for regular expressions. Commented Aug 6, 2018 at 17:15
  • Your example doesn't work, right? I don't see anything that inserts the __ after the link's closing parenthesis. Commented Aug 6, 2018 at 17:17
  • 1
    @NRitH the example isn't complete as its just an indication of the route i was going to take.... Commented Aug 6, 2018 at 19:58

1 Answer 1

1

I'm using the following String extension that allows you to find strings that match a certain regex pattern and replace it with some other string:

extension String {
    mutating func replaceOccurrence(ofPattern pattern: String, with replacementString: String) {
        do {
            let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
            self = regex.stringByReplacingMatches(in: self, options: [], range: NSMakeRange(0, utf16.count), withTemplate: replacementString)
        } catch { print("ERROR: searchFor regex (\(pattern)) on string (\(self)) failed") }
    }
}

Then, you could replace (\[.*?\)) with __$1__, like this:

str.replaceOccurrence(ofPattern: "(\\[.*?\\))", with: "__$1__")

Explanation

...in case you're unfamiliar with regular expressions:

The regex:

( - opening parenthesis, that creates a new group which is later used to insert the matched string back into the replacement string
\[ - matches a bracket; needs to be escaped using \ to disable the bracket's regex meaning & match the actual character instead
.* - matches any character...
? - ...until...
\) - ...the next closing parenthesis; this one also needs to be escaped to match the actual character, and not create a new group
) - closes the group

The replacement:

__ - your replacement string: opening bold range in this case
$1 - inserts the previously matched group here __ - again, your replacement string: closing bold range in this case

Fun-Fact: in Swift, you need to escape escaping characters, like \\ to make sure the code compiles, because Xcode thinks, you're trying to escape a character from the string at compile-time.
That's why the regex isn't (\[.*?\)), but (\\[.*?\\)).

Sign up to request clarification or add additional context in comments.

14 Comments

Hey thanks @Linus - this looks really good - however there are a couple of issues. I ideally want to just amend the text in place rather than pulling out specific sections: for instance running the following : do { let regex = try NSRegularExpression(pattern: "(\[.*?\))" , options: [.caseInsensitive]) var newString = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.utf16.count), withTemplate: "$1") print("First regex (newString)") } catch { print("ERROR: searchFor regex (("(\[.*?\))")) on string ((str)) failed") }
only returns First regex Some bold text _FIRST LINK, more bold text._
Also I need to run the same for the italic - which changing the pattern to '"$1"' returns Some bold text FIRST LINK, more bold text.
Sorry regex is something I have never mastered :(
No problem. I’m having a hard time to understand what you’re actually trying to do, as I apparently misunderstood it at least in some way. Can you please, in a clean and compact example, show what exactly you’re trying to do? @user499846
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.