Regular Expression to match parentheses and brackets for JavaScript

22,289

Solution 1

This should work:

/\([^)]*\)|\[[^\]]*\]/g;

Try it out below:

var str = "The (quick) brown [fox]";

var re = /\([^)]*\)|\[[^\]]*\]/g;

str.match(re).forEach(function(m) {
  document.body.insertAdjacentHTML('beforeend', m + '<br>');
});

Regex101

Solution 2

Here is the solution I use, based on popular xregexp package by Steve Levithan.
Note that left and right params are regx expressions so the solution can handle more difficult scenarios. Solution correctly handles nested parenteses as welll. Refer to http://xregexp.com/api/#matchRecursive for more details and options.

const XRegExp = require('xregexp');

// test: match ${...}
matchRecursive('${a${b}c} d${x} ${e${}${f}g}', '\\${', '}').forEach(match => {
    console.log(match.innerText);
});

/* yields:
a${b}c
x
e${}${f}g
*/

interface XRegExpPart { start: number; end: number; name: string; value: string; }
export interface XRegExpMatch { index: number; outerText: string; innerText: string; left: string; right: string; }

export function replaceRecursive(text: string, left: string, right: string, replacer: (match: XRegExpMatch) => string, flags: string = 'g', escapeChar?: string): string {
    const matches: XRegExpMatch[] = matchRecursive(text, left, right, flags, escapeChar);
    let offset: number = 0;

    for (const match of matches) {
        const replacement = replacer(match);
        if (replacement == match.outerText) continue;
        text = replaceAt(text, match.index + offset, match.outerText.length, replacement);
        offset += replacement.length - match.outerText.length;
    }
    return text;
}

export function matchRecursive(text: string, left: string, right: string, flags: string = 'g', escapeChar?: string): XRegExpMatch[] {
    // see: https://github.com/slevithan/xregexp#xregexpmatchrecursive
    // see: http://xregexp.com/api/#matchRecursive
    const parts: XRegExpPart[] = XRegExp.matchRecursive(text, left, right, flags, { valueNames: [null, 'left', 'match', 'right'], escapeChar: escapeChar });
    const matches: XRegExpMatch[] = [];
    let leftPart: XRegExpPart;
    let matchPart: XRegExpPart;

    for (const part of parts) {
        // note: assumption is made that left, match and right parts occur in this sequence
        switch (part.name) {
            case 'left':
                leftPart = part;
                break;
            case 'match':
                matchPart = part;
                break;
            case 'right':
                matches.push({ index: leftPart!.start, innerText: matchPart!.value, outerText: leftPart!.value + matchPart!.value + part.value, left: leftPart!.value, right: part.value });
                break;
            default:
                throw new Error(`Unexpected part name: '${part.name}'.`);
        }
    }

    return matches;
}

export function replaceAt(string: string, index: number, length: number, replacement: string): string {
    return string.substr(0, index) + replacement + string.substr(index + length);
}
Share:
22,289
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I have this regex that matches text inside parentheses:

    /\([^\)]*?\)/g
    

    I want to be able to match both parentheses and brackets so it will detect both parentheses and brackets in a string so I can color it.

    This should be the string:

    The (quick) brown [fox]
    

    I want to color (quick) and [fox] so I need the regex to match both parentheses and brackets.

    Thanks.

  • RomanPerekhrest
    RomanPerekhrest almost 8 years
    how about this string "The (quick] brown [fox)" ?
  • SamWhan
    SamWhan almost 8 years
    @RomanPerekhrest What about it? As said, it'll match all words (or phrases) inside brackets, any of [, ( and ], ).
  • timolawl
    timolawl almost 8 years
    @RomanPerekhrest Thank you for your input. Can you provide an example where I need to specify the lazy operator? I can't think of one.
  • RomanPerekhrest
    RomanPerekhrest almost 8 years
    it will mix it, without determining which one wrapped only with brackets, and witch - with parenthesis only
  • RomanPerekhrest
    RomanPerekhrest almost 8 years
    it's not difficult. "The (quick) brown [fox] The (quick) brown [fox] The (quick) brown [fox] The (quick) brown [fox]". Are you still hesitating about "lazy" operator?
  • RomanPerekhrest
    RomanPerekhrest almost 8 years
    Secondly, test this input string var str = "The (function test(quick){ body }) brown [fox]";. What if one needs that function definition within "parent" brackets?
  • timolawl
    timolawl almost 8 years
    @RomanPerekhrest I understand your concern. Without the OP having further specify the use case, I won't add more specificity to the regex as it may be unnecessary. Concerning your string, I've tested it and the lazy operator doesn't seem to be needed. (Check out the updated Regex101!). Thanks for the feedback.
  • SamWhan
    SamWhan almost 8 years
    @RomanPerekhrest Exactly. That's why I stated the flaw in the answer - "It would allow mixing of brackets like ..." ;)
  • JulianSoto
    JulianSoto over 6 years
    \w will break special characters like á or ñ.
  • Toto
    Toto over 4 years
    What question are you anwsering? OP didn't talk about nested structure.
  • T. Jastrzębski
    T. Jastrzębski over 4 years
    Hi did not specify text inside parentheses cannot contain matched or unmatched parentheses. Solution I propose can handle such case - unmatched parentheses has to be escaped.