【问题标题】:How do I make my preg_replace only look for the words while they are NOT within an <acronym> tag?如何让我的 preg_replace 只查找不在 <acronym> 标签内的单词?
【发布时间】:2026-01-22 08:40:01
【问题描述】:

在 PHP 中,我有一个字符串 $string 和一个数组 $acronyms(格式为 "UK" => "United Kingdom")。

现在我想用一些 HTML 标签替换 $string 中的所有首字母缩写词。例如Hello UK 应该变成Hello &lt;acronym title="United Kingdom"&gt;UK&lt;/acronym&gt;&lt;/pre&gt;

我是这样做的:

foreach($acronyms as $acronym => $tooltip){
     $string = preg_replace('/'.$acronym.'/i', ''.$acronym.'', $string);
}

问题是:假设我有一个文本Hello UK,并且有一个数组将“UK”替换为“United Kingdom”,将“Kingdom”替换为“RandomWord”。然后文本将替换为Hello &lt;acronym title="United &lt;acronym title="RandomWord"&gt;Kingdom&lt;/acronym&gt;"&gt;UK&lt;/acronym&gt;,这显然是混乱的。

所以问题是:如何让我的 preg_replace 只查找不在 &lt;acronym&gt; 标签内的单词?(既不在标题属性中,也不在标签本身内)

编辑:根据响应进行第二次尝试(因为我无法回复代码)。仍然是同样的问题,首字母缩略词中的文本被第二次替换......

foreach($acronyms as $acronym => $tooltip){
        $acronyms[$acronym] = '<acronym title="'.$tooltip.'">'.$acronym.'</acronym>';
}
$string = str_ireplace(array_keys($acronyms), array_values($acronyms), $string);

【问题讨论】:

  • 先去掉所有首字母缩写词,然后再添加。
  • 哦,通常这样的替换要么在客户端(根据 Javascript)上完成,要么以不改变源的方式完成。那么你的问题就不会出现。

标签: php regex preg-replace acronym


【解决方案1】:

您可以使用strtr()。执行替换后不会重新扫描字符串:

foreach ($acronyms as $acronym => $tooltip) {
    $acronyms[$acronym] = sprintf('<acronym title="%s">%s</acronym>',
        htmlspecialchars($tooltip),
        htmlspecialchars($acronym)
    );
}

echo strtr($str, $acronyms);

【讨论】:

    【解决方案2】:

    这是正则表达式版本的尝试:

    foreach($acronyms as $acronym => $tooltip){
        $rexp = '/' . $acronym . '(?!((?!<acronym).)*<\/acronym>)/i';
        $string = preg_replace($rexp, ''.$acronym.'', $string);
    }
    

    似乎对我有用。它执行以下操作:

    1. 将 $acronym 变量与否定前瞻匹配...
    2. 可以找到结束首字母缩略词标记的位置
    3. 但当首字母缩略词标签在其前面时停止前瞻。

    最终,这只匹配不在首字母缩略词标签内的地方(包括标题等所有属性)。

    这是一个实际应用的例子:gSkinner regex example

    【讨论】:

      【解决方案3】:

      不要试图用正则表达式做所有事情:

      1. 使用 HTML/XML 解析库解析您的 HTML。
      2. 遍历您的 HTML 标记,替换您必须替换的内容。
      3. 请您的“html 解析库”将其转换回“HTML 字符串”。

      【讨论】: