Dino
Dino

Reputation: 352

Match last occuring enclosing outer brackets

I tried now for three hours to construct the following regex match without much success. I have the following two strings:

This is a test string to illustrate the problem (example) in complex matching logic (Work / not working (in this case) to match this last occurring bracket closure)

and

Simpler version of the string (Matchable in any easy way)

I would like to define a str.match() that matches this last part of the strings above. Resulting in:

Work / not working (in this case) to match this last occurring bracket closure

and

Matchable in any easy way

Any good way to achieve this? Sadly the data is highly volatile that a strong Regex is much rather preferred instead of long functional logic. Thanks so much!

Upvotes: 3

Views: 704

Answers (3)

Downgoat
Downgoat

Reputation: 14361

RegEx is really impractical for this. Your regex would have to be extremely long, and will always have it's limitations. I really recommend using some parser. I like to use balanced.js.

var lastItem = balanced.matches({
    source: string,
    open: '(',
    close: ')'
}).map(function (match) {
    return string.substr(match.index + match.head.length, match.length - match.head.length - match.tail.length);
}).filter(function (a, b, c) {
    return b === c.length - 1;
})[0] || "";

Fiddle

Results:

Simpler version of the string (Matchable in any easy way)

Matchable in any easy way

Upvotes: 1

Ry-
Ry-

Reputation: 224984

You can’t match arbitrarily deeply nested parentheses with regular expressions. Some regular expression engines have been extended in such a way that they can parse that kind of grammar, but JavaScript’s has not; you’ll need to match manually.

function lastParenthesizedSubstring(text) {
    var end = text.lastIndexOf(')');
    var i = end - 1;
    var nesting = 1;

    while (nesting > 0) {
        if (i < 0) {
            // Parenthesis imbalance! You may want to throw
            // an exception or something.
            return null;
        }

        var c = text.charAt(i);

        if (c === ')') {
            nesting++;
        } else if (c === '(') {
            nesting--;
        }

        i--;
    }

    return text.substring(i + 2, end);
}

Upvotes: 4

Downgoat
Downgoat

Reputation: 14361

Couldn't think of anything better. This also isn't 100% RegEx. Assume string is your string

var matches = string.match(/(\([^(]*\))/g),
    result  = matches[matches.length-1].substring(0, matches[matches.length-1].length - 1);

Limitations

  • Only allows one level deep parentheses
  • Only can of one, one level deep parentheses

Upvotes: -1

Related Questions