| Ticket UUID: | 524b35a8b5f9ec643fc323582217193d91247430 | ||
| Title: | can't force regex subexpression greediness as stated by man page | ||
| Type: | Bug | Created on: | 2019-05-12 18:45:58 |
| Submitter: | tgl | Assigned to: | nobody |
| Subsystem: | 43. Regexp | Severity: | Minor |
| Priority: | 5 Medium | Last modified: | 2026-10-10 18:18:30 |
| Status: | Open | Closed by: | nobody |
| Resolution: | None | Closed on: | |
| Version: | 8.6.18, 9.0.5, 9.1.0 | ||
| Description: | ||||
The re_syntax man page states
The quantifiers \fB{1,1}\fR and \fB{1,1}?\fR can be used to
force longest and shortest preference, respectively, on a
subexpression or a whole RE.
However, this doesn't actually work reliably, for example
% regexp -inline {^(l*)(.*)(f*)$} {llmmmfff}
llmmmfff ll mmmfff {}
% regexp -inline {^(l*){1,1}?(.*)(f*)$} {llmmmfff}
llmmmfff ll mmmfff {}
The first result is fine, but the second result should have been
llmmmfff {} llmmmfff {}
that is, the (l*) should have been forced to be non-greedy.
I tracked this down to an over-optimistic optimization in parseqatom():
it throws away a {1,1} quantifier without regard to whether it's trying to impose
a different greediness than the atom would have natively.
This seems to be sufficient to fix it:
@@ -1155,7 +1155,10 @@ parseqatom(struct vars *v,
/* rest of branch can be strung starting from atom->end */
s2 = atom->end;
}
- else if (m == 1 && n == 1)
+ else if (m == 1 && n == 1 &&
+ (qprefer == 0 ||
+ (atom->flags & (LONGER | SHORTER | MIXED)) == 0 ||
+ qprefer == (atom->flags & (LONGER | SHORTER | MIXED))))
{
/* no/vacuous quantifier: done */
EMPTYARC(s, atom->begin); /* empty prefix */
(That's from a draft Postgres patch, your formatting of the code is different)
BTW, I think that the weasel wording in the NOTE in re_syntax.n immediately
after the above-quoted bit is due to this bug.
Background at
https://www.postgresql.org/message-id/flat/20583.1557680147%40sss.pgh.pa.us
| ||||
| User Comments: | ||||
jan.nijtmans added on 2019-05-12 20:31:56:
Proposed fix committed in bug-524b35a8b5 branch. No test-case yet. serhiy.storchaka added on 2026-10-10 18:18:30:
Still the same in 8.6, 9.0 and 9.1: parseqatom() dropped every {1,1} as vacuous, so {1,1}? could not make a greedy atom non-greedy, and {1,1} could not make a non-greedy atom greedy (e.g. (.*?){1,1}(.*)), contrary to re_syntax.n. Proposed fix in branch regexp-1-1-quantifier-preference: your patch, which keeps the quantifier when it asks for a different preference than the atom has. With it, the results agree with PostgreSQL on the example and on other {1,1} and {1} cases. Tests reg-25.4 to 25.9. Branch bug-524b35a8b5 had the same change without tests, based on core-8-5-branch. | ||||
