php / php/php-src

preg_match is inconsistent in how it handles unmatched capturing groups

Open
#17,934 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Extension: pcre Status: Needs Triage
Dominant language
C
Stars
40.4k
Forks
8.1k
Avg merge
2d 13h
Merged PRs (30d)
96

Description

Description

The following code:

<?php
$pattern = '/A(?<a>a)|B(?<b>b)/';
preg_match($pattern, 'Aa', $matches);
echo json_encode($matches)."\n";
preg_match($pattern, 'Bb', $matches);
echo json_encode($matches)."\n";

Resulted in this output:

{"0":"Aa","a":"a","1":"a"}
{"0":"Bb","a":"","1":"","b":"b","2":"b"}

But I expected this output instead:

{"0":"Aa","a":"a","1":"a"}
{"0":"Bb","b":"b","2":"b"}

I would expect that a capturing group only appears in the match if the pattern captured that group. However, it seems like in some cases groups on the left side of an alternation will appear with an empty string as the value while groups on the right side are omitted when they aren't captured.

This makes it difficult to easily ask "Did group N get captured?" because, depending on the structure of the regex, sometimes "not captured" will report as empty string and sometimes it will report as an omitted key. The problem is even more confusing if empty string was a possible capture for the group; in that case there's no way to tell what happened without using PREG_OFFSET_CAPTURE which gives -1 for the extraneous matches.

PHP Version

PHP 8.2.12

Operating System

Windows 11

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the preg_match example on PHP 8.2.12 and compare the matches arrays for both alternation branches. Trace the handling of unmatched capturing groups in the preg_match implementation, then add or update a regression test so unmatched groups have consistent output and the shown expected result is produced.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.