I have some code where, if the value of $subtitle1
contains only letters or spaces, a regex replace works fine. When $subtitle1
string begins with a digit (for example "3rd Edition") the preg_replace function works unexpectedly. If I add a space in the replacement string, then the value of $subtitle1 can start with a digit and its ok, but it puts an unwanted space before the 3 in "3rd Edition".
$raw_xml = '<property name="subtitle1" type="String">Linux is more than a shell</property>';
$subtitle1 = '3rd Edition';
$replacers = array (
'/(<property name="subtitle1" type="String">)([1-9A-Za-z ]+)(<\/property>)/' => sprintf("$1%s$3",$subtitle1), //1
'/(<property name="subtitle1" type="String">)([1-9A-Za-z ]+)(<\/property>)/' => sprintf("$1 %s$3",$subtitle1), //2
'/(<property name="subtitle1" type="String">)([1-9A-Za-z ]+)(<\/property>)/' => sprintf("$1%s$3",$subtitle1), //3
);
echo preg_replace(array_keys($replacers), array_values($replacers), $raw_xml);
//1 (when $subtitle1 = 'Third Edition', outputs: <property name="subtitle1" type="String">Third Edition</property>)
//2 (when $subtitle1 = '3rd Edition', outputs: <property name="subtitle1" type="String"> 3rd Edition</property>)
//3 (when $subtitle1 = '3rd Edition', outputs: rd Edition</property>)
Is there something I can do differently to get this to work the same provided that the type of $subtitle1
var is always a string? I've tried modifiers s, U, but did not get any further. Thanks for any insight into this.
On a purely theoretical plane your code does not work cause the parser search for the backreferences $1
and $3
as variables before the string is evaluated by the sprintf or the pcre regex engine.
So to make it works simply replace the sprintf
literal string section:
sprintf("$1%s$3",$subtitle1) -> sprintf('${1}%s${3}',$subtitle1)
# Note the change of $1 -> ${1} to clearly delimit the backreference
# and the use of single quote string '...' instead of "..."
# (inside double quotes any $ start an evaluation as variables of string beside)
But for a reliable solution avoid to parse xml with regex and use a specialized (simple and powerful) parser like this:
<?php
$xml = <<<XML
<properties> <!-- Added -->
<property name="subtitle1" type="String">Linux is more than a shell</property>
</properties>
XML;
$properties = new SimpleXMLElement($xml);
$properties->property[0] = '3rd Edition';
echo $properties->asXML(); //Only the first is changed
See more on the Official Docs .
The problem is because: sprintf("$1%s$3",$subtitle1)
output: $13rd Edition$3
.
I guess that the regex engine understand it as the 13th capturing group.
The good new is, I found a solution for you.
Replace: $subtitle1 = '3rd Edition'
;
By: $subtitle1 = '>3rd Edition<';
and extract the <> from your first and third capturing group just like this.
$replacers = array (
'/(<property name="subtitle1" type="String")>([1-9A-Za-z ]+)<(\/property>)/' => sprintf("$1%s$3",$subtitle1), //1
'/(<property name="subtitle1" type="String")>([1-9A-Za-z ]+)<(\/property>)/' => sprintf("$1 %s$3",$subtitle1), //2
'/(<property name="subtitle1" type="String")>([1-9A-Za-z ]+)<(\/property>)/' => sprintf("$1%s$3",$subtitle1), //3
);
You can test it here: http://sandbox.onlinephpfunctions.com/code/05bf9a209bdcd6622bf494dc7f4887660e7a93a0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.