Split string with regex based on two conditions

I would like to split this string:

lg:[:after]:hover:color-blue

The two conditions are:

  1. Split by :
  2. If there’s a [], get the content (even if there’s a : inside)

The result would be

  • lg
  • :after
  • hover
  • color-blue

Possible inputs would be:

  • [:after]:hover:color-blue
  • hover:color-blue
  • lg:hover:color-blue

What I have so far:

const regex = /(?:([^\:\[\]]+)|\[([^\[\]]+)\])/g;

const matches = [...string.matchAll(regex)].map((match) =>
  typeof match[2] !== "undefined" ? match[2] : match[1]
);

It works well but the map feels hacky.

Is there a way to get the desired output directly from the regex?

>Solution :

Yes:

(?<=\[)[^[\]]+(?=])   # 1+ non-square-brackets inside a pair of those
|                     # or
(?<=^|:)[^[\]:]+      # 1+ non-square-brackets-or-colons
                      # preceded by either the start of string or a colon.

Try it on regex101.com.

Note that we need to use .match() instead of .split():

string.match(/(?<=\[)[^[\]]+(?=])|(?<=^|:)[^[\]:]+/g)

Try it:

console.config({ maximize: true });

const testcases = [
  'lg:[:after]:hover:color-blue',
  '[:after]:hover:color-blue',
  'hover:color-blue',
  'lg:hover:color-blue'
];

const regex = /(?<=\[)[^[\]]+(?=])|(?<=^|:)[^[\]:]+/g;

for (const testcase of testcases) {
  console.log(testcase.match(regex));
}
<script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Leave a Reply