marcnyc
marcnyc

Reputation: 585

RegEx to match value of a variable or a string (with or without quotes)

Here is my dilemma:

I wrote this RegEx pattern which works in my sandbox but does not work on my website:

Sandbox: http://regex101.com/r/vP3uG4

Pattern:

(.*[$]'.$variable.'\s*=\s*\'?)(.*?)(\'?;.*)

The line of code goes like this:

$savedsettings_new = preg_replace('/(.*[$]'.$variable.'\s*=\s*\'?)(.*?)(\'?;.*)/is','$1'. $value .'$3',$savedsettings_temp);

As you can see it works on the sandbox but it doesn't work live.

I am trying to match values of variables that can be expressed as strings (with single quotes around them) or numerical values with no quotes, like so:

$match_string = 'value';
$match_number = 1;

Right now this code works fine with strings but with numerical variables that are not enclosed in strings I just get the contents of the backreference $3 and I don't get anything at all before that!

I'm scratching my head and really can't figure out why it works on RegEx101 but not live... Aren't I doing the right thing when matching for one or no single quotes (and escaping them because the preg_replace has quotes?

Upvotes: 2

Views: 1313

Answers (2)

revo
revo

Reputation: 48741

If the variable $value contains a numerical value then the replacement pattern in your preg_replace will look like this: $12$3

That's true but not as you expected. In Regex Engine, $ddd or here $dd (which are equal to \ddd and \dd) are treated as octal numbers.

So in this case $12 means a octal index 12 which is equal to a kind of space in ASCII.

In the case of working with these tricky issues in Regular Expressions you should wrap your backreference number within {} so it should be ${1}2${3}

Change your replacement pattern to '${1}'.$value.'${3}'

Upvotes: 1

Amal Murali
Amal Murali

Reputation: 76636

Okay, found out the issue. The solution is to wrap the backreference in ${}.

Quoting the PHP manual:

When working with a replacement pattern where a backreference is immediately followed by another number (i.e.: placing a literal number immediately after a matched pattern), you cannot use the familiar \\1 notation for your backreference. \\11, for example, would confuse preg_replace() since it does not know whether you want the \\1 backreference followed by a literal 1, or the \\11 backreference followed by nothing. In this case the solution is to use \${1}1.

So, your code should look like:

header('Content-Type: text/plain');

$variable = 'tbs_development';
$value = '333';

$savedsettings_temp = <<<'CODE'
$tbs_underconstruction = 'foo';
$tbs_development = 0;
CODE;

$pattern = '/(.*[$]'.preg_quote($variable).'\s*=\s*\'?)(.*?)(\'?;.*)/is';
$replacement = '${1}'.$value.'${3}';

$savedsettings_new = preg_replace($pattern, $replacement, $savedsettings_temp);

echo $savedsettings_new;

Output:

$tbs_underconstruction = 'foo';
$tbs_development = 333;

Demo.

Upvotes: 2

Related Questions