]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152056: Compile single-category character sets to a bare CATEGORY opcode (GH-152057)
authorPieter Eendebak <pieter.eendebak@gmail.com>
Wed, 24 Jun 2026 11:09:50 +0000 (13:09 +0200)
committerGitHub <noreply@github.com>
Wed, 24 Jun 2026 11:09:50 +0000 (11:09 +0000)
A character set containing exactly one category, e.g. [\d] or [^\s], now
compiles to a single CATEGORY opcode (like \d or \S) instead of an IN
block.  The negated form maps to the complementary category.  This speeds
up matching and reduces the size of the compiled byte code.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Doc/whatsnew/3.16.rst
Lib/re/_parser.py
Misc/NEWS.d/next/Library/2026-06-24-10-30-00.gh-issue-152056.Qk7mZ2.rst [new file with mode: 0644]

index e3f04739e3b49d56f77238934a8eb37dd315c94c..f9e54cde10afe0337080e2e6874583f93065199d 100644 (file)
@@ -288,10 +288,12 @@ re
 --
 
 * Character class escapes (``\d``, ``\D``, ``\s``, ``\S``, ``\w`` and ``\W``)
-  outside a character set are now compiled to a single ``CATEGORY`` opcode
-  instead of being wrapped in an ``IN`` block.  This speeds up matching of
-  patterns such as ``\d+`` and reduces the size of the compiled byte code.
-  (Contributed by Serhiy Storchaka in :gh:`152033`.)
+  outside a character set, and character sets containing a single such escape
+  (such as ``[\d]`` or ``[^\s]``), are now compiled to a single ``CATEGORY``
+  opcode instead of being wrapped in an ``IN`` block.  This speeds up matching
+  of patterns such as ``\d+`` and reduces the size of the compiled byte code.
+  (Contributed by Serhiy Storchaka in :gh:`152033` and Pieter Eendebak in
+  :gh:`152056`.)
 
 module_name
 -----------
index 3c41c43409534b800301ffee1f38dce5ca79aad4..b8c19cd3070c4df26d3924c6f94e776fbe99d584 100644 (file)
@@ -625,6 +625,12 @@ def _parse(source, state, verbose, nested, first=False):
                     subpatternappend((NOT_LITERAL, set[0][1]))
                 else:
                     subpatternappend(set[0])
+            elif _len(set) == 1 and set[0][0] is CATEGORY:
+                # optimization: a lone category like [\d] or [^\d]
+                if negate:
+                    subpatternappend((CATEGORY, CH_NEGATE[set[0][1]]))
+                else:
+                    subpatternappend(set[0])
             else:
                 if negate:
                     set.insert(0, (NEGATE, None))
diff --git a/Misc/NEWS.d/next/Library/2026-06-24-10-30-00.gh-issue-152056.Qk7mZ2.rst b/Misc/NEWS.d/next/Library/2026-06-24-10-30-00.gh-issue-152056.Qk7mZ2.rst
new file mode 100644 (file)
index 0000000..6e71d72
--- /dev/null
@@ -0,0 +1,5 @@
+Optimize matching of a character set that contains a single character
+category, such as ``[\d]`` or ``[^\s]``: it is now compiled to a single
+``CATEGORY`` opcode, the same as the corresponding ``\d`` or ``\S`` escape,
+instead of being wrapped in an ``IN`` block.  This speeds up matching and
+reduces the size of the compiled byte code.  Patch by Pieter Eendebak.