【问题标题】:Having trouble replacing a value in a tag when a string variable starts with digit当字符串变量以数字开头时,无法替换标记中的值
【发布时间】:2016-01-08 17:51:19
【问题描述】:

我有一些代码,如果$subtitle1 的值仅包含字母或空格,则正则表达式替换可以正常工作。当$subtitle1 字符串以数字开头(例如“3rd Edition”)时,preg_replace 函数会意外工作。如果我在替换字符串中添加一个空格,那么 $subtitle1 的值可以以数字开头并且可以,但它会在“3rd Edition”中的 3 之前放置一个不需要的空格。

$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>)

如果$subtitle1 var 的类型始终是字符串,我是否可以做一些不同的事情来使其工作相同?我已经尝试过修饰符 s、U,但没有更进一步。感谢您对此的任何见解。

【问题讨论】:

    标签: php regex string preg-replace


    【解决方案1】:

    在纯理论层面上,您的代码不起作用导致解析器在 sprintf 或 pcre 评估字符串之前搜索 反向引用 $1$3 作为变量 正则表达式引擎。

    所以要使其正常工作,只需替换 sprintf 文字字符串部分:

    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)
    

    但是为了获得可靠的解决方案避免使用正则表达式解析 xml 并使用专门的(简单而强大的)解析器,如下所示:

    <?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
    

    Official Docs 上查看更多信息。

    【讨论】:

    • 感谢您的建议。它可以工作,将来我将使用 SimpleXMLElement 进行探索。
    【解决方案2】:

    问题是因为:sprintf("$1%s$3",$subtitle1)

    输出:$13rd Edition$3

    我猜正则表达式引擎将其理解为第 13 个捕获组。

    好消息是,我为你找到了解决方案。

    替换:$subtitle1 = '3rd Edition';

    作者:$subtitle1 = '&gt;3rd Edition&lt;';

    并像这样从您的第一个和第三个捕获组中提取 。

    $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
    );
    

    你可以在这里测试它:http://sandbox.onlinephpfunctions.com/code/05bf9a209bdcd6622bf494dc7f4887660e7a93a0

    【讨论】:

    • 谢谢。我已经相应地修改了模式,现在它按预期工作。我没有添加“>”和“'/(<property name="subtitle1" type="String")>([1-9A-Za-z ]+)<(\/property>)/' => sprintf("$1>%s<$3", $subtitle1 ),,以便标签完整,并正确捕获字符串。再次感谢您的帮助。
    猜你喜欢
    • 2018-04-04
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 2019-12-28
    • 2023-01-07
    • 1970-01-01
    • 2021-06-20
    相关资源
    最近更新 更多