user6631314
user6631314

Reputation: 1976

Find string pattern within pattern in string using regex or other method Swift

I am looking for a way to identify a character pattern within a character pattern and delete any inner examples of the pattern, if they exist, to leave only the outer ones.

An example would be:

str = "some text [outer part [inner part] back to outer part] more text"

I'd like to delete the inner pattern [ ] to leave:

str = "some text [outer part inner part back to outer part] more text"

This is not always the format. One could also see:

 str = "this text [does does no need inner brackets removed] as there aren't any"

 str = "this text [does does not]  need inner brackets [removed] as there aren't any"

 str = "this text [has one [instance] of inner brackets] and another [that is] okay"

Note: if differing open and close delimiters are an issue, I can change them to one delimiter such as a * but I still want to get rid of the inner delimiters.

This seems straightforward but is proving harder than I expected as str_replace doesn't naturally detect which is outer and which is inner. For example, in the following I can find the character [ but not sure how to only delete if it is inside another [...

let string = "some text [outer part [inner part] back to outer part] more text"

if string.range(of: "[\b(?=.*[)[a-zA-Z]{1,8}\b", options: [.regularExpression, caseInsensitive]) != nil {
print("found a match")
} else {
print("no match present")
}

Thanks for any suggestions.

Upvotes: 0

Views: 93

Answers (2)

Leo Dabus
Leo Dabus

Reputation: 236508

You can find the first index of the closing bracket and then search the last index of an opening brackets up to that index. Then you can check the substrings before and after if they have an opening and closing brackets:

extension StringProtocol where Self: RangeReplaceableCollection {
    mutating func removeInnerBrackets() {
        if let close = firstIndex(of: "]"),
            let open = self[..<close].lastIndex(of: "["),
            let _ = self[..<open].firstIndex(of: "["),
            let _ =  self[index(after: close)...].firstIndex(of: "]") {
            remove(at: close)
            remove(at: open)
        }
    }
}

var sentence = "some text [outer [part [inner part] back to outer] part] more text"
sentence.removeInnerBrackets()
sentence // "some text [outer [part inner part back to outer] part] more text"

Upvotes: 1

Dante Puglisi
Dante Puglisi

Reputation: 668

What about something like this:

func removeInnerDelimiters(S: String) -> String {
    var S = S
    var lastOpeningCharPos = -1
    var closingCharPos = -1
    for (index, c) in S.enumerated() {
        if c == "[" {
            lastOpeningCharPos = index
        } else if c == "]" {
            closingCharPos = index
            break
        }
    }
    if lastOpeningCharPos > -1 && closingCharPos > 0 {
        S.remove(at: S.index(S.startIndex, offsetBy: closingCharPos))
        S.remove(at: S.index(S.startIndex, offsetBy: lastOpeningCharPos))
    }
    return S
}

So basically you go through the whole String and when you find the first ] you just remove the last [ you found and of course that ]

Upvotes: 0

Related Questions