简体   繁体   English

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

[英]How can I replace the Nth instance of a string in PHP?

I need to dynamically add an active class to a shortcode in wordpress based on the active number set in it's parent shortcode. 我需要根据其父简码中设置的有效数字为wordpress中的简码动态添加一个有效类。

The parent looks like this: 父母看起来像这样:

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

The $content variable can technically consist of anything in between the shortcodes tags, but specifically, should include more child shortcodes (it's a tabs shortcode so the parent is tabs and the children are tab). 从技术上说,$ content变量可以由shortcodes标记之间的任何内容组成,但是具体来说,应该包含更多的子级短代码(这是一个tabs短代码,因此父级是tabs,子级是tab)。

What I need to do is parse $content and replace the Nth ( $active variable) instance of [vc_tab with [vc_tab active="true" 我需要做的是解析$content并将[vc_tab的第N个( $active变量)实例[vc_tab[vc_tab active="true"

I realize there are better ways to design the shortcode to compensate for this but I am limited in what I can do because I am modifying Visual Composer to use Bootstrap tabs instead of jQuery and Bootstrap tabs need the active class on both the <li> and the <div class="tab-pane"> elements but I don't want the users to have to add an active number to the parent shortcode and an active true/false to the child as that will get confusing. 我意识到有更好的方法来设计短代码来弥补这一点,但是我只能做些限制,因为我正在修改Visual Composer以使用Bootstrap选项卡而不是jQuery,并且Bootstrap选项卡在<li><div class="tab-pane">元素,但我不希望用户必须在父简码中添加一个有效数字,在子代中添加一个有效的true / false,因为这会造成混淆。

So far from googling I can only find replacing the first occurrence or all occurrences, not the Nth one. 到目前为止,我只能查找代替第一个或所有出现的位置,而不是第N个出现的位置。

Temporarily I am using jQuery to make the appropriate <div> active but it results in an undesirable FOUC where there is no pane visible on load and then one pops into place when the jQuery runs. 暂时,我正在使用jQuery激活适当的<div>但它导致了不良的FOUC,即在加载时没有可见的窗格,然后在运行jQuery时弹出一个窗格。

$('.tabs-wrap').each(function(){
  var activeTab = $(this).find('.tabbed li.active a').attr('href');
  $(this).find(activeTab).addClass('active');
});  

I 'm not familiar with the tools you mention so I can't say if there is a better way to achieve the end goal, but you can replace the Nth occurrence of something using preg_replace_callback : 我不熟悉您提到的工具,因此无法确定是否有更好的方法来实现最终目标,但是您可以使用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 . 看到它在行动

This works by replacing each occurrence with itself unless the occurrence counter is equal to the target number. 除非事件计数器等于目标编号,否则通过用自身替换每个事件来进行工作。

Note that I have passed $active as the maximum number of occurrences to replace in order to get free performance increase; 请注意,我已经通过$active作为替换的最大次数来获得免费的性能提升。 this will cause preg_replace_callback to stop after $active occurrences have been replaced (we know that all occurrences after that will be replaced by themselves, so there's no point in going on). 这将导致preg_replace_callback在替换$active事件后停止(我们知道之后的所有事件都将被它们自己替换,因此没有意义了)。

This is an interesting problem, and got me thinking if you really need a regex to do this. 这是一个有趣的问题,让我想如果你真的需要一个正则表达式来做到这一点。

My conclusion is that I don't believe you do. 我的结论是,我不相信你。 All you need to do is find the occurrence of the Nth $needle , and replace it with your replacement. 您需要做的就是找到Nth $needle ,并将其替换为替换项。 This can be achieved through some simple string manipulation, as follows: 这可以通过一些简单的字符串操作来实现,如下所示:

  1. Define some variables. 定义一些变量。 Your input string, your $active index, the $needle that we are looking for, and the $replace ment that we will replace the Nth match with. 您的输入字符串,您的$active索引,我们要寻找的$needle以及将替换第Nth匹配项的$replace replacement。

     $string = "[vc_tab [vc_tab [vc_tab [vc_tab [vc_tab [vc_tab"; $active = 3; $needle = "[vc_tab"; $replace = '[vc_tab active="true"'; 
  2. Now, we need to make sure that there are enough $needle s in the $string , otherwise we can't do this replacement. 现在,我们需要确保$string中有足够的$needle ,否则我们将无法进行替换。

     if( substr_count( $string, $needle) < $active) { throw new Exception("There aren't enough needles in the string to do this replacement"); } 
  3. Now, we know we can do the replacement. 现在,我们知道可以进行替换了。 So let's find the $index in the string where the Nth occurrence of $needle ends: 因此,让我们在Nth次出现的$needle结尾的字符串中找到$index

     $count = 0; $index = 0; while( $count++ < $active) { $index = strpos( $string, $needle, $index) + strlen( $needle); } 
  4. Now, $index is pointing here in the string: 现在, $index在字符串中指向此处:

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

    We can now do some simple substr() 's to form the final string: 现在,我们可以执行一些简单的substr()来形成最终的字符串:

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

    So, we end up concatenating: 因此,我们最终进行了串联:

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

This results in our final output : 结果是我们的最终输出

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

Try it out in the demo ! 演示中尝试一下!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM