Reputation: 8906
There is a string some parts of which are marked w/brackets:
abc(de)f(uv)xyz
How to split it into parts like:
abc | false
de | true
f | false
uv | true
xyz | false
Where true stands for a bracketed part and false stands for an unbracketed one.
N.B. Brackets are only used for marking purpose. Nested, unpaired brackets and other complex scenarious are not possible.
Upvotes: 0
Views: 49
Reputation: 1746
Given that the bracket sequence is guaranteed to be valid and not to contain nested sequences, we can keep the regular expression quite simple:
\(?([^()]+)\)?
\(?
- optionally accept an opening bracket([^()]+)
- capture anything that’s not an opening or closing bracket\)?
- optionally accept a closing bracketOnce we execute the regex (execAll(pattern, text)
) we get
const matches = execAll(pattern, text)
[
['abc', 'abc'],
['(de)', 'de'],
['f' , 'f' ]
['(uv)', 'uv'],
['xyz', 'xyz']
]
Index 0
of each entry is the matched text and index 1
is the captured group.
Looking at the first character of index 0
tells us whether it’s a group or not:
matches[0][0] === '(' // false
matches[1][0] === '(' // true
We want the text first and the boolean second:
matches.map(([bracket, group]) => [group, bracket[0]==='('])
[
['abc', false],
['de' , true ],
['f' , false]
['uv' , true ],
['xyz', false]
]
Done!
const execAll = (pattern, str) => {
const result=[]
let match
while((match = pattern.exec(str))) {
result.push(match)
}
return result
}
const extractGroups = text => {
const pattern = /\(?([^()]+)\)?/g
const matches = execAll(pattern, text)
return matches
.map(([bracket, group]) => [group, bracket[0]==='('])
}
console.log(extractGroups('abc(de)f(uv)xyz'))
Upvotes: 1