0

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.

1
  • It does indeed seem straightforward. What's your regex pattern? Commented Jul 3, 2020 at 21:48

2 Answers 2

1

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"
Sign up to request clarification or add additional context in comments.

Comments

0

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 ]

3 Comments

I don't know if there will be a nested [] or not. In some cases, there isn't.
Maybe you could save the indices of the [ and ] as you find them in an array if you have more than one [ in a row as in [[, you delete the right most one and similarly for ]] the leftmost one. I will try that
This was just to explain the idea, of course you have to make sure all edge-cases work. If there's no "[" but there's a "]" for example this would fail horribly. I'll edit to take that case into account.

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.