Repository navigation
sed: keep a quantifier after another quantifier greedy - #642
qodelicious wants to merge 2 commits into
Conversation
In POSIX regexes a+? repeats a+ zero or one times and a*+ repeats a* one or more times. The regex engines read the second one as a lazy or possessive modifier, so put the repeated part in a non-capturing group first. Also have ensure_dotall add (?s) in front of a pattern that starts with such a group, rather than reading the group as a flag group.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #642 +/- ##
==========================================
+ Coverage 95.07% 95.16% +0.08%
==========================================
Files 14 14
Lines 7459 7634 +175
Branches 441 460 +19
==========================================
+ Hits 7092 7265 +173
- Misses 366 368 +2
Partials 1 1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 4.17%1 warning
Performance Changes
Tip Curious why performance improved? Comment Comparing |
| pos += 1; | ||
| } | ||
| // The rest of a multi-byte UTF-8 character. | ||
| 0x80..=0xbf => { |
There was a problem hiding this comment.
in byte mode these bytes are whole characters, no?
a\xa9+? becomes (?:a\xa9+)? here, GNU with LC_ALL=C reads it as a(?:\xa9+)?
please pass the character mode and add a test
There was a problem hiding this comment.
You're right, in byte mode those are whole characters. It now gets the character mode and only skips 0x80-0xbf as continuation bytes in UTF-8 mode, so with LC_ALL=C a\xa9+? becomes a(?:\xa9+)?. Added a unit test for both modes and a LC_ALL=C test in test_sed.rs (s/a\xa9+?/X/ on ab gives Xb, same as GNU).
| } | ||
|
|
||
| #[test] | ||
| fn test_quantifier_after_quantifier_stays_greedy() { |
There was a problem hiding this comment.
could you please run the GNU testsuite too?
git clone https://github.com/mirror/sed.git ../gnu.sed
./util/run-gnu-testsuite.sh
There was a problem hiding this comment.
Ran it with the branch on top of current main. 19 pass / 30 fail / 16 skip, same as main test by test, both with LC_ALL=C and in a UTF-8 locale. So no regressions, but nothing new passes either (the skips are the multibyte locale tests, I don't have those locales here).
In a POSIX regex a quantifier right after another one applies to the whole repeated part. So
b+?is(b+)?andb*+is(b*)+, both greedy. The regex engines read a?or+there as a lazy or possessive modifier instead, so sed gave different results from GNU.BREs hit it too with
\+\?.Now
compile_regexputs the repeated part in a non-capturing group before a stacked quantifier, soab+?becomesa(?:b+)?. Escapes, bracket expressions and groups count as the thing being repeated.ensure_dotallread a leading(?:as a flag group and turned(?:b+)?into(?:b+s)?, so it now puts(?s)in front of a group like that.Added
test_quantifier_after_quantifier_stays_greedy(all cases checked against GNU sed 4.9) and unit tests for the rewrite and forensure_dotall. The integration test fails on main and passes with the change.