如何使用PHP替换“所有之间”的内容?

29
$string = "<tag>i dont know what is here</tag>"
$string = str_replace("???", "<tag></tag>", $string);
echo $string; // <tag></tag>

那么我需要找什么代码?

8个回答

34

一个通用函数:

function replace_between($str, $needle_start, $needle_end, $replacement) {
    $pos = strpos($str, $needle_start);
    $start = $pos === false ? 0 : $pos + strlen($needle_start);

    $pos = strpos($str, $needle_end, $start);
    $end = $pos === false ? strlen($str) : $pos;

    return substr_replace($str, $replacement, $start, $end - $start);
}

演示


3
不必使用正则表达式,除非需要。请将文本内容翻译成俚语、专业术语、优雅流畅的风格。 - user428517
@sgroves 当正则表达式避免代码混乱或提供其他合理的优势时,它是一个合理的工具。 - mickmackusa
1
我在PHP 7中尝试了这个,但没有输出结果,似乎它也剥离了标签 - 同时我想知道是否有一个选项适用于所有出现的情况,即超过1组标签和文本之间。 - kerry

26
$search = "/[^<tag>](.*)[^<\/tag>]/";
$replace = "your new inner text";
$string = "<tag>i dont know what is here</tag>";
echo preg_replace($search,$replace,$string);

输出:

<tag>your new inner text</tag>

我假设您想要替换标签的内容,而不仅仅是替换整个字符串。 - rlemon
说实话应该使用正向/反向预查。 - Steve Wang
3
这个答案完全错误。它只是碰巧提供了所需的输出。当输入略微改变时,请注意此答案失败。https://3v4l.org/p507L 这是对否定字符类的错误使用,会给研究人员带来错误信息。@faq - mickmackusa
4
如果你认为有更好的答案,请提供,但我绝不会说这个答案是“100% 错误”的,因为它在撰写时做到了它需要做的事情(而且 OP 明确地同意了)。 - rlemon
答案不正确,因为它仅适用于给定的示例。对于这样的输入:$string = "BEGIN <tag>i dont know what is here</tag> MIDDLE <tag>i dont know what is here</tag> END"; 你会得到错误的结果。要获得正确的解决方案,您应该使用以下代码: $search = "/^<tag>[^</tag>]/"; $search = '#(<tag>).*?(</tag>)#'; $replace = "new text"; $string = "BEGIN <tag>inside tag</tag> MIDDLE <tag>second tag</tag> END"; echo preg_replace($search, '$1'.$replace.'$2', $string); 代码链接:https://3v4l.org/pD61r - Sergiu Sandrean
显示剩余3条评论

14
$string = "<tag>I do not know what is here</tag>";
$new_text = 'I know now'; 
echo preg_replace('#(<tag.*?>).*?(</tag>)#', '$1'.$new_text.'$2' , $string); //<tag>I know now</tag>

1
您在第二个参数中缺少替换字符串:'$1'.'new text'.'$2'。 - gradosevic

4
如果“tag”发生变化:
$string = "<tag>i dont know what is here</tag>";
$string = preg_replace('|^<([a-z]*).*|', '<$1></$1>', $string)
echo $string; // <tag></tag>

观看这个未解释的答案摧毁比它应该摧毁的更多的内容:https://3v4l.org/HBRYV - mickmackusa
回答没有上下文。 - user3934058

4

通用非正则表达式解决方案:

我修改了@felix-kling的答案。现在它只会替换文本,如果找到了指定的词。

此外,我添加了参数,以替换指定的词、指定起始位置和替换所有匹配项。

我使用了mb_函数,使该函数支持多字节字符安全处理。 如果您需要不区分大小写的解决方案,请将mb_strpos调用替换为mb_stripos

function replaceBetween($string, $needleStart, $needleEnd, $replacement,
                        $replaceNeedles = false, $startPos = 0, $replaceAll = false) {
    $posStart = mb_strpos($string, $needleStart, $startPos);

    if ($posStart === false) {
        return $string;
    }

    $start = $posStart + ($replaceNeedles ? 0 : mb_strlen($needleStart));
    $posEnd = mb_strpos($string, $needleEnd, $start);

    if ($posEnd === false) {
        return $string;
    }

    $length = $posEnd - $start + ($replaceNeedles ? mb_strlen($needleEnd) : 0);

    $result = substr_replace($string, $replacement, $start, $length);

    if ($replaceAll) {
        $nextStartPos = $start + mb_strlen($replacement) + mb_strlen($needleEnd);

        if ($nextStartPos >= mb_strlen($string)) {
            return $result;
        }

        return replaceBetween($result, $needleStart, $needleEnd, $replacement, $replaceNeedles, $nextStartPos, true);
    }

    return $result;
}

$string = "{ Some} how it {is} here{";

echo replaceBetween($string, '{', '}', '(hey)', true, 0, true); // (hey) how it (hey) here{

3
$string = "<tag>i dont know what is here</tag>"
$string = "<tag></tag>";
echo $string; // <tag></tag>

或者只是这样?
$string = str_replace($string, "<tag></tag>", $string);

抱歉,我忍不住了。也许您可以在问题中添加更多细节。;)


完全没有必要在答案中加入这样的话。一条注释也足够了。 - user3934058

3
如果您不知道<tag>标签内部的内容,那么可能存在另一个<tag>标签,例如:
<tag>something<tag>something else</tag></tag>

因此,一个普通的字符串替换函数无法完成这项工作。

更健壮的解决方案是将字符串视为XML,并使用DOMDocument进行操作。诚然,这仅在字符串有效为XML时才起作用,但我仍然认为它比字符串替换更好。

$string = "<tag>i don't know what is here</tag>";
$replacement = "replacement";

$doc = new DOMDocument();
$doc->loadXML($str1);
$node = $doc->getElementsByTagName('tag')->item(0);
$newNode = $doc->createElement("tag", $replacement); 
$node->parentNode->replaceChild($newNode, $node);
echo $str1 = $doc->saveHTML($node); //output: <tag>replacement</tag>

这几乎是一个可行的答案。我做了一些调整。https://3v4l.org/phEOf 总的来说,如果可以使用DomDocument,应该使用它来提高稳定性。 - mickmackusa

2
如果您需要替换整个部分,那么这个函数很有用:
$var = "Nate";

$body = "Hey there {firstName} have you already completed your purchase?";

$newBody = replaceVariable($body,"{","}",$var);

echo $newBody;

function replaceVariable($body,$needleStart,$needleEnd,$replacement){
  while(strpos($body,$needleStart){
      $start = strpos($body,$needleStart);
      $end = strpos($body,$needleEnd);
      $body = substr_replace($body,$replacement,$start,$end-$start+1);
  }
  return $body;
}

我必须替换一个提交到文本区域的变量。因此,我用 Nate 替换了 firstName(包括花括号)。


这个方法很好,没有使用正则表达式。但是只有当你想要替换字符串的一个实例时才有效。如果你需要替换多个实例,你必须使用循环直到strpos返回FALSE(这意味着没有任何实例可以再被替换了)。 - Julien Fastré
注意:这个表达式 strpos($body,$needleEnd); 会从字符串的开头开始搜索。如果要从 needle 开始搜索,您需要一个偏移量:strpos($body,$needleEnd, $needleStart); - AlexSp3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接