php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #61214 puzzled replace when replacement contains "="
Submitted: 2012-03-01 08:25 UTC Modified: 2012-03-01 08:35 UTC
From: 58219758 at qq dot com Assigned:
Status: Not a bug Package: PCRE related
PHP Version: 5.3.10 OS: windows 7
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: 58219758 at qq dot com
New email:
PHP Version: OS:

 

 [2012-03-01 08:25 UTC] 58219758 at qq dot com
Description:
------------
$search = array('/required/','/min\=(\d+)/','/max\=(\d+)/','/\w+\=([^=]+)/',);
$replace2 = array('R=1','R="$1"','R="$1"',);
It seems doesn't work correctly when replacement contains "="

Test script:
---------------
$search = array('/required/','/min\=(\d+)/','/max\=(\d+)/','/\w+\=([^=]+)/',);
$replace1 = array('R1','R"$1"','R"$1"',);
$replace2 = array('R=1','R="$1"','R="$1"',);
$replace3 = array('R\\=1','R\\="$1"','R\\="$1"',);
$from = 'required min=3 max=5 code=code';
echo preg_replace($search, $replace1, $from);
echo preg_replace($search, $replace2, $from);
echo preg_replace($search, $replace3, $from);

Expected result:
----------------
R1 R"3" R"5"
R=1 R="3" R="5"
R\=1 R\="3" R\="5"

Actual result:
--------------
R1 R"3" R"5"
 ="3" =code
R\=1 R\="3" R\="5"

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-03-01 08:35 UTC] rasmus@php.net
-Status: Open +Status: Not a bug
 [2012-03-01 08:35 UTC] rasmus@php.net
This is not a bug. '=' has special meaning in ?= and ?<= expressions and it is on 
the list of characters quotes by preg_quote.
 [2012-03-01 09:59 UTC] 58219758 at qq dot com
"=" will be quoted to "\=", in this case, the result is R\=1 R\="3" R\="5" too, whenever "\=" or "\\=".
 [2012-03-01 10:03 UTC] 58219758 at qq dot com
$search = array(
	'/required/',
	'/min\=(\d+)/',
	'/max\=(\d+)/',
	'/\w+\=([^=]+)/',
);
$replace2 = array(
	'R=1',
	'R="$1"',
	'R="$1"',
);
in this case, the result is still ="3" =code
 [2012-03-01 18:04 UTC] anon at anon dot anon
This is happening because of the fourth search expression /\w+\=([^=]+)/. It matches the previous replacements and removes them. Without it, this:

echo preg_replace(
	array('/required/', '/min\=(\d+)/', '/max\=(\d+)/'),
	array('R=1', 'R="$1"', 'R="$1"'),
	'required min=3 max=5 code=code'
) . "\n";

Outputs:

R=1 R="3" R="5" code=code

(As expected.) But the replacements happen one after the other instead of simultaneously, so then it will do the equivalent of this:

echo preg_replace(
	'/\w+\=([^=]+)/',
	'',
	'R=1 R="3" R="5" code=code'
) . "\n";

..which will match and remove 'R=1 R' and 'R="5" code', producing the "puzzling" output:

="3" =code

Here is one way to solve it, by doing all the matches simultaneously with one regexp:

echo preg_replace_callback(
	'/(\w+)(?:=(\S+))?/',
	function ($parts) {
		if (!empty($parts[2])) { // have '='
			if ($parts[1] == 'min' || $parts[1] == 'max') {
				return 'R="' . $parts[2] . '"';
			} else {
				return '';
			}
		} else {
			if ($parts[1] == 'required') {
				return 'R=1';
			} else {
				return $parts[0]; // unmodified
			}
		}
	},
	'required min=3 max=5 code=code'
) . "\n";

This outputs:

R=1 R="3" R="5"
 [2012-03-02 02:01 UTC] 58219758 at qq dot com
Thank you very much!
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Tue May 06 19:01:28 2025 UTC