RegExp: fix match count computation
* There actually is a way to count the matches, so use it instead of attempting to guess * In some cases (when using optional groups (xxx)?, for example), there may be a non-matching group (with offsets set to -1) and matching groups after it, so the binary search wasn't quite working * Instead, we always return the number of capturing groups in the in the given expression, which is the maximal number of matches. Some (or all) of these may not have any content. We do return 0 matches on any error, including when the regular expression didn't match anything.
This commit is contained in:
@@ -154,40 +154,17 @@ struct RegExp::MatchResultData : public BReferenceable {
|
||||
fMatchCount(0),
|
||||
fMatches(NULL)
|
||||
{
|
||||
// Do the matching: Since we need to provide a buffer for the matches
|
||||
// for regexec() to fill in, but don't know the number of matches
|
||||
// beforehand, we need to guess and retry with a larger buffer, if it
|
||||
// wasn't large enough.
|
||||
size_t maxMatchCount = 32;
|
||||
for (;;) {
|
||||
fMatches = new regmatch_t[maxMatchCount];
|
||||
if (regexec(compiledExpression, string, maxMatchCount, fMatches, 0)
|
||||
!= 0) {
|
||||
delete[] fMatches;
|
||||
fMatches = NULL;
|
||||
fMatchCount = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fMatches[maxMatchCount - 1].rm_so == -1) {
|
||||
// determine the match count
|
||||
size_t lower = 0;
|
||||
size_t upper = maxMatchCount;
|
||||
while (lower < upper) {
|
||||
size_t mid = (lower + upper) / 2;
|
||||
if (fMatches[mid].rm_so == -1)
|
||||
upper = mid;
|
||||
else
|
||||
lower = mid + 1;
|
||||
}
|
||||
fMatchCount = lower;
|
||||
break;
|
||||
}
|
||||
|
||||
// buffer too small -- try again with larger buffer
|
||||
// fMatchCount is always set to the number of matching groups in the
|
||||
// expression (or 0 if an error occured). Some of the "matches" in
|
||||
// the array may still point to the (-1,-1) range if they don't
|
||||
// actually match anything.
|
||||
fMatchCount = compiledExpression->re_nsub + 1;
|
||||
fMatches = new regmatch_t[fMatchCount];
|
||||
if (regexec(compiledExpression, string, fMatchCount, fMatches, 0)
|
||||
!= 0) {
|
||||
delete[] fMatches;
|
||||
fMatches = NULL;
|
||||
maxMatchCount *= 2;
|
||||
fMatchCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user