如何在PHP中替换字符串的第N个实例?

时间:2013-08-15 20:10:41

标签: php regex wordpress preg-replace preg-match

我需要根据在其父级短代码中设置的活动数字,动态地将活动类添加到wordpress中的短代码中。

父母看起来像这样:

$active = 3;
$output .= "\n\t\t".wpb_js_remove_wpautop($content);

$ content变量在技术上可以包含在短代码标签之间的任何内容,但具体来说,应该包含更多子短代码(它是一个选项卡短代码,因此父级是制表符,子级是制表符)。

我需要做的是解析$content并将$active的第{({1}}个}变量)实例替换为[vc_tab

我意识到有更好的方法可以设计短代码来弥补这一点,但我可以做的事情有限,因为我正在修改Visual Composer以使用Bootstrap选项卡而不是jQuery和Bootstrap选项卡需要{的两个活动类{1}}和[vc_tab active="true"元素,但我不希望用户必须向父级短代码添加活动数字,并为子级添加活动的true / false,因为这会让人感到困惑。

远离谷歌搜索我只能找到替换第一次出现或所有出现,而不是第N次出现。

暂时我正在使用jQuery来使相应的<li>处于活动状态,但是它导致了一个不合需要的FOUC,其中加载时没有可见的窗格,然后在jQuery运行时弹出一个窗格。

<div class="tab-pane">

2 个答案:

答案 0 :(得分:3)

我不熟悉您提到的工具,所以我不能说是否有更好的方法来实现最终目标,但您可以使用preg_replace_callback替换第N次出现:

$active = 3;     // target occurrence
$occurrence = 0; // counter
$output = preg_replace_callback(
    '/\[vc_tab/',
    function ($matches) use(&$occurrence, $active) {
        return ++$occurrence != $active
            ? $matches[0]
            : '[vc_tab active="true"';
    },
    $output,
    $active
);

<强> See it in action

除非出现计数器等于目标数量,否则这可以通过将每个事件替换为自身来实现。

请注意,我已将$active作为要替换的最大出现次数,以获得免费的性能提升;这将导致preg_replace_callback$active次更换后停止(我们知道之后的所有事件都会被自己替换,所以没有必要继续)。

答案 1 :(得分:3)

这是一个有趣的问题,让我想到如果你真的需要一个正则表达式来做到这一点。

我的结论是我不相信你这样做。您需要做的就是找到Nth $needle的出现位置,并将其替换为您的替代品。这可以通过一些简单的字符串操作来实现,如下所示:

  1. 定义一些变量。您的输入字符串,$active索引,我们要查找的$needle以及$replace我们将替换Nth匹配。

    $string  = "[vc_tab [vc_tab [vc_tab [vc_tab [vc_tab [vc_tab";
    $active  = 3;
    $needle  = "[vc_tab";
    $replace = '[vc_tab active="true"';
    
  2. 现在,我们需要确保$needle中有足够$string个,否则我们无法替换。{/ p>

    if( substr_count( $string, $needle) < $active) {
        throw new Exception("There aren't enough needles in the string to do this replacement");
    }
    
  3. 现在,我们知道我们可以替换。因此,让我们在$index出现Nth的字符串中找到$needle

    $count = 0; $index = 0;
    while( $count++ < $active) {
        $index = strpos( $string, $needle, $index) + strlen( $needle);
    }
    
  4. 现在,$index指向字符串:

    [vc_tab [vc_tab [vc_tab [vc_tab [vc_tab [vc_tab
                           ^
                           Here
    

    我们现在可以做一些简单的substr()来形成最终的字符串:

    $result = substr( $string, 0, $index - strlen( $needle)) . $replace . substr( $string, $index);
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^^^^^^^^^
              Before the Nth match                                        After the Nth match
    

    所以,我们最终连接:

    • [vc_tab [vc_tab
    • [vc_tab active="true"
    • [vc_tab [vc_tab [vc_tab
  5. 这会产生我们的final output

    [vc_tab [vc_tab [vc_tab active="true" [vc_tab [vc_tab [vc_tab
    

    the demo中试用!