GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-152100: Fuse set-operation character classes into a single charset by serhiy-storchaka · Pull Request #152214 · python/cpython

Conversation

@serhiy-storchaka

@serhiy-storchaka serhiy-storchaka commented Jun 25, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

A compile-time optimization for the set operations added in gh-152100. No behaviour change -- same matches, fewer engine steps.

The parser lowers set difference [A--B] to A(?<![B]): a character class followed by a negative lookbehind. But the engine's charset() walk treats every NEGATE as a polarity toggle (see Modules/_sre/sre_lib.h), so one character set can express the difference directly -- [NEGATE] B [NEGATE] A matches A minus B in a single charset test instead of a charset match plus a lookbehind rescan.

A new pass in Lib/re/_optimizer.py performs two folds:

  • Set difference [A--B] (or an explicit A(?<![B])) into the single charset [NEGATE] B [NEGATE] A. _optimize_charset is made segment-aware so the interior NEGATE compiles correctly; the parser keeps emitting the plain A(?<![B]) form.
  • A union with a non-flat operand such as [0-9||[a-z--b]] is left by the parser as a BRANCH it cannot merge; once its alternatives are all one-character matchers, their item lists are concatenated into one IN.

Besides removing the lookbehind rescan, the fused charset also becomes the INFO prefix, so the engine can fast-skip non-matching positions. On scan-heavy input this is several times faster (findall over 50 KB of non-matching text, best of 7):

[a-z--aeiou]       5.6x
[\w--\d]           5.3x
[0-9||[a-z--b]]    9.4x

On match-dense input the per-match win is smaller, masked by match-object construction.

  • Issue: Support set operations in regular expression character classes #152100

🤖 Generated with Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@serhiy-storchaka @claude
pythongh-152100: Fuse set-operation character classes into a single c…
7233606
…harset

Add a compile-time optimization pass (Lib/re/_optimizer.py) that rewrites
set-operation character classes into a single character set where the
engine's charset() representation allows it.  charset() treats every NEGATE
as a polarity toggle, so a mid-list NEGATE expresses set difference and a
flat run expresses union.

Set difference -- [A--B], emitted by the parser as A(?<![B]) -- fuses into
the charset [NEGATE] B [NEGATE] A, matching A minus B in one test instead of
a charset match plus a lookbehind rescan.  _optimize_charset is made
segment-aware so the interior NEGATE compiles correctly.

A union with a non-flat operand, such as [0-9||[a-z--b]], is emitted by the
parser as a BRANCH that it cannot merge.  Once its alternatives are all
one-character matchers, their item lists are concatenated into a single IN.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@bedevere-app bedevere-app Bot mentioned this pull request Jun 25, 2026
Support set operations in regular expression character classes #152100
Open
@bedevere-app bedevere-app Bot added the awaiting core review label Jun 25, 2026
@serhiy-storchaka serhiy-storchaka added the skip news label Jun 25, 2026
@serhiy-storchaka
serhiy-storchaka merged commit d91e103 into python:main Jun 26, 2026
96 of 98 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting core review label Jun 26, 2026
@serhiy-storchaka
serhiy-storchaka deleted the re-set-ops branch June 26, 2026 11:12
@fedonman fedonman mentioned this pull request Aug 18, 2026
gh-155985: Do not fuse a set difference under IGNORECASE with LOCALE #155993
Closed
@eendebakpt eendebakpt mentioned this pull request Nov 1, 2026
Regression in re.compile() performance #161125
Open
@SHURIKA6 SHURIKA6 mentioned this pull request Nov 8, 2026
gh-161125: Avoid redundant work in regex compilation #161600
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

skip news

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@serhiy-storchaka
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.