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:
Adrien Destugues
2013-10-16 21:01:42 +02:00
parent a905216770
commit 831819980e
+9 -32
View File
@@ -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;
}
}