Tcl Source Code

View Ticket
Login
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.