Highlighting separate groups
Important: in this implementation two branches of code process separate groups, which one, depending on the existence of d
flag.
- Primitive, base on
indexOf()
, only reliable with contiguous groups - unwanted group(s) can be easily filtered out. - Exact, but not all browsers currently supported group
indices
.
- Case without
wrapAllRanges
option:- They both have identical logic for nested groups - if a parent group has been marked, there is no way to mark nested groups.
This means you can use a nested group(s) as auxiliary and don't care about filtering them.
- They both have identical logic for nested groups - if a parent group has been marked, there is no way to mark nested groups.
- Case
wrapAllRanges : true
:- With
acrossElements
option, the primitive one wrap a whole match as a group 0 and then all groups that are child of match[0] as a nested (see Example). - The exact one wrap all nested groups - you need to filter nested an auxiliary group(s).
- With
They have different parent groups logic:
- The exact one does allow using a parent group as an auxiliary - you need to filter out it in order to mark a nested group(s).
- The primitive one does not allow this - if a parent group has filtered out, a nested group(s) won't be marked.
To test the primitive branch compatibility, just add the d
flag.
There is no strict requirement for the contiguity of capturing groups.
Compare: string - 'AAB xxx BCD xx BC', to mark groups AB and BC
- in
/(AB)\b.+?\b(BC)/g
the indexOf('BC', start) find first 'BC', which is correct - in
/(AB)\b(.+?)\b(BC)(?!D)/g
the indexOf('BC', start) also find first 'BC', which is wrong, because of condition '(?!D)', so group 2 is required.
Warning: related using RegExp without the d
flag:
- Do not add a capturing group(s) to lookbehind assertion
(?<=)
, there is no code which handles such cases. - With
acrossElements
option, it is not possible to highlight a capturing group(s) inside a lookahead assertion(?=)
.
See markRegExp() method about info
object properties used in filter
and each
callbacks.
How to filter matches see Filtering matches.
How to highlight nesting groups see Nesting groups.
Filtering capturing groups:
instance.markRegExp(/(AB)\b(.+)\b(?<gr3>CD)?(.+)(EF)\b/gi, {
// 'acrossElements' : true,
'separateGroups' : true,
'filter' : (textNode, matchString, matchesSoFar, info) => {
// To filter any group use info.groupIndex - a current group index
// Note: if a group lays across several elements, the index be the same while a group is wrapping
if (info.groupIndex === 2 || info.groupIndex === 4) return false;
// also can be used a group content
// if (matchString === 'AB') return false;
// To filter a whole match on a group presence
// Note: it iterates through all groups and only then returns
if (info.match[3]) return true/false;
// or
// also can be used a named capturing group
if (info.match.groups.gr3) return true/false;
return true;
},
});
Example to mark separate groups with acrossElements
option:
let groupCount = 0, gr1Count = 0, gr2Count = 0;
instance.markRegExp(/(AB)\b.+?\b(CD)/gi, {
'acrossElements' : true,
'separateGroups' : true,
'each' : (markElement, info) => {
// info.count - matches count so far
// if start of match group
if (info.groupStart) {
// all group count
groupCount++;
// info.groupIndex is the index of a current match group
if (info.groupIndex === 1) {
markElement.className = 'group1-1';
gr1Count++;
} else if (info.groupIndex === 2) {
markElement.className = 'group2-1';
gr2Count++;
}
}
}
});
Example to mark separate groups without acrossElements
option:
let count = 0, gr1Count = 0;
instance.markRegExp(/(AB).+?(CD)/gi, {
'separateGroups' : true,
'each' : (markElement, info) => {
// all group count
count++;
if (info.groupIndex === 1) {
// an individual group count
gr1Count++;
}
}
});