2

I am looking for an easier (and less hacky) way to get the substring of what is inside matching square brackets in a string. For example, lets say this is the string:

[ABC[D][E[FG]]HIJK[LMN]]OPQR[STUVW]XYZ

I want the substring:

ABC[D][E[FG]]HIJK[LMN]

Right now, I am looping through the string and counting the open and closed brackets, and when those numbers are the same, I take substring of the first open bracket and last closed bracket.

Is there an easier way to do this (ie with regex), so that I do need to loop through every character?

5
  • Do you also want to match/capture [STUVW]? Commented Mar 21, 2015 at 18:20
  • @Mathletics No, that is not needed. Commented Mar 21, 2015 at 18:25
  • 3
    You're parsing a little language, with nesting. There is nothing hacky whatsoever about iterating over the characters in the input--that's what parsers do. What would be hacky is a hard-to-read, hard-to-maintain, limited regexp such as was suggested in one answer. Commented Mar 21, 2015 at 18:45
  • @torazaburo Hey, thanks, I think your right; I am just going to leave it as is. I just thought that if there was an easier and clean way with regex, I could use that instead. Commented Mar 21, 2015 at 19:36
  • Is this an array? What is this supposed to be? Commented Mar 22, 2015 at 2:02

3 Answers 3

1

Here's another approach, an ugly hack which turns the input into a JS array representation and then parses it using JSON.parse:

function parse(str) {
    return JSON.parse('[' +
        str.split('') . join(',') .  // insert commas
            replace(/\[,/g, '[')  .  // clean up leading commas
            replace(/,]/g, ']')   .  // clean up trailing commas
            replace(/\w/g, '"$&"')   // quote strings
        + ']');
}

>> hack('A[B]C')
<< ["A", ["B"], "C"]

Now a stringifier to turn arrays back into the bracketed form:

function stringify(array) {
    return Array.isArray(array) ? '[' + array.map(stringify).join('') + ']' : array;
}

Now your problem can be solved by:

stringify(parse("[ABC[D][E[FG]]HIJK[LMN]]OPQR[STUVW]XYZ")[0])
Sign up to request clarification or add additional context in comments.

Comments

0

Not sure if I get the question right (sorry about that).

So you mean that if you were to have a string of characters X, you would like to check if the string combination Y is contained within X?

Where Y being ABC[D][E[FG]]HIJK[LMN]

If so then you could simply do:

var str = "[ABC[D][E[FG]]HIJK[LMN]]OPQR[STUVW]XYZ"; var res = str.match(/ABC\[D]\[E\[FG]]HIJK\[LMN]/);

The above would then return the string literal Y as it matches what is inside str.

It is important that you pay attention to the fact that the symbols [ are being escaped with a \. This is because in regex if you were to have the two square brackets with any letter in between (ie. [asd]) regex would then match the single characters included in the specified set.

You can test the regex here: https://regex101.com/r/zK3vZ3/1

1 Comment

Aha, so literally, why not just res = 'ABC[D][E[FG]]HIJK[LMN]'?
0

I think the problem is to get all characters from an opening square bracket up to the corresponding closing square bracket. Balancing groups are not implemented in JavaScript, but there is a workaround: we can use several optional groups between these square brackets.

The following regex will match up to 3 nested [...] groups and you can add the capturing groups to support more:

\[[^\]\[]*(?: \[[^\]\[]*(?: \[[^\]\[]*(?:\[[^\]\[]*\])*\] )*[^\]\[]* \][^\]\[]* )*[^\]\[]* \]

See example here. However, performance may be not that high with such heavy backtracking.

UPDATE

Use XRegExp:

var str = '[ABC[D][E[FG]]HIJK[LMN]]OPQR[STUVW]XYZ';

// First match:
var res = XRegExp.matchRecursive(str, '\\[', ']');
document.body.innerHTML = "Getting the first match:<br/><pre>" + JSON.stringify(res, 0, 4) + "</pre><br/>And now, multiple matches (add \"g\" modifier when defining the XRegExp)";

// Multiple matches:
res = XRegExp.matchRecursive(str, '\\[', ']', 'g');
document.body.innerHTML += "<pre>" + JSON.stringify(res, 0, 4) + "</pre>";
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/2.0.0/xregexp-all-min.js"></script>

Comments

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.