【问题标题】:PHP Regular expression to match keyword outside HTML tag <a>PHP正则表达式匹配HTML标签<a>之外的关键字
【发布时间】:2011-12-09 13:47:16
【问题描述】:

我一直在尝试使用正则表达式来匹配和替换部分 HTML 中出现的关键字:

  1. 我想匹配keyword&lt;strong&gt;keyword&lt;/strong&gt;
  2. &lt;a href="someurl.html" target="_blank"&gt;keyword&lt;/a&gt;&lt;a href="someur2.html"&gt;already linked keyword &lt;/a&gt; 不应匹配

我只对匹配(和替换)第一行的 keyword 感兴趣。

我想要这个的原因是用&lt;a href="dictionary.php?k=keyword"&gt;keyword&lt;/s&gt; 替换keyword,但只有当keyword 不在&lt;a&gt; 标记内时。

任何帮助将不胜感激!

【问题讨论】:

  • 我清理了一下,因为格式很不正确,但我不确定我的更正是否完全正确... tixastronauta,如果我的“修复”引入了错误,请编辑并更正他们。

标签: php html regex


【解决方案1】:
$str = preg_replace('~Moses(?!(?>[^<]*(?:<(?!/?a\b)[^<]*)*)</a>)~i',
                    '<a href="novo-mega-link.php">$0</a>', $str);

负前瞻内的表达式匹配到下一个结束&lt;/a&gt; 标记,但前提是它没有首先看到一个开始&lt;a&gt; 标记。如果成功,则意味着单词 Moses 在锚元素内,因此前瞻失败,并且没有匹配发生。

这是一个demo

【讨论】:

  • 谢谢艾伦,但您的正则表达式也替换了 &lt;a&gt; 标记内的关键字“moses”。因此,在您的示例中:but &lt;a href="original-moses1.html"&gt;Moses&lt;/a&gt; supposes erroneously; 变为:but &lt;a href="original-&lt;a href="novo-mega-link.php"&gt;moses&lt;/a&gt;1.html"&gt;&lt;a href="novo-mega-link.php"&gt;Moses&lt;/a&gt;&lt;/a&gt; supposes erroneously; 而我没有希望这发生。
  • 对不起。我正在尝试在前瞻中使用\s 而不是\b(这不起作用),但不小心把它留在了里面。
  • 如何修改为不替换 img alt="" 属性中的关键字?
  • 好吧,单选alt 属性是没有意义的;出于此目的,标签内发生的任何匹配都是无效的。防止这些匹配的前瞻要简单得多:(?![^&lt;]*+&gt;).
  • 谢谢,但是当一个词或短语被多个关键字匹配时,这会产生一些意想不到的后果——它将 标签放在 标签中,例如:好处">补偿
【解决方案2】:

我设法做到了我想做的事(不使用正则表达式):

  • 解析字符串的每个字符
  • 删除所有&lt;a&gt; 标记(将它们复制到临时数组并在字符串上保留占位符)
  • str_replace 新字符串以替换所有关键字
  • 用原来的&lt;a&gt;标签重新填充占位符

这是我使用的代码,以防其他人需要它:

$str = <<<STRA
Moses supposes his toeses are roses,
but <a href="original-moses1.html">Moses</a> supposes erroneously;
for nobody's toeses are posies of roses,
as Moses supposes his toeses to be.
Ganda <span class="cenas"><a href="original-moses2.html" target="_blank">Moses</a></span>!
STRA;

$arr1 = str_split($str);

$arr_links = array();
$phrase_holder = '';
$current_a = 0;
$goto_arr_links = false;
$close_a = false;

foreach($arr1 as $k => $v)
{
    if ($close_a == true)
    {
        if ($v == '>') {
            $close_a = false;
        } 
        continue;
    }

    if ($goto_arr_links == true)
    {
        $arr_links[$current_a] .= $v;
    }

    if ($v == '<' && $arr1[$k+1] == 'a') { /* <a */
        // keep collecting every char until </a>
        $arr_links[$current_a] .= $v;
        $goto_arr_links = true;
    } elseif ($v == '<' && $arr1[$k+1] == '/' && $arr1[$k+2] == 'a' && $arr1[$k+3] == '>' ) { /* </a> */
        $arr_links[$current_a] .= "/a>";

        $goto_arr_links = false;
        $close_a = true;
        $phrase_holder .= "{%$current_a%}"; /* put a parameter holder on the phrase */
        $current_a++;
    }    
    elseif ($goto_arr_links == false) {
        $phrase_holder .= $v;
    }
}

echo "Links Array:\n";
print_r($arr_links);
echo "\n\n\nPhrase Holder:\n";
echo $phrase_holder;
echo "\n\n\n(pre) Final Phrase (with my keyword replaced):\n";
$final_phrase = str_replace("Moses", "<a href=\"novo-mega-link.php\">Moses</a>", $phrase_holder);
echo $final_phrase;
echo "\n\n\nFinal Phrase:\n";
foreach($arr_links as $k => $v)
{
    $final_phrase = str_replace("{%$k%}", $v, $final_phrase);
}
echo $final_phrase;

输出:

链接数组:

Array
(
    [0] => <a href="original-moses1.html">Moses</a>
    [1] => <a href="original-moses2.html" target="_blank">Moses</a>
)

短语持有人:

Moses supposes his toeses are roses,
but {%0%} supposes erroneously;
for nobody's toeses are posies of roses,
as Moses supposes his toeses to be.
Ganda <span class="cenas">{%1%}</span>!

(pre)最终短语(替换了我的关键字):

<a href="novo-mega-link.php">Moses</a> supposes his toeses are roses,
but {%0%} supposes erroneously;
for nobody's toeses are posies of roses,
as <a href="novo-mega-link.php">Moses</a> supposes his toeses to be.
Ganda <span class="cenas">{%1%}</span>!

最后一句话:

<a href="novo-mega-link.php">Moses</a> supposes his toeses are roses,
but <a href="original-moses1.html">Moses</a> supposes erroneously;
for nobody's toeses are posies of roses,
as <a href="novo-mega-link.php">Moses</a> supposes his toeses to be.
Ganda <span class="cenas"><a href="original-moses2.html" target="_blank">Moses</a></span>!

【讨论】:

    【解决方案3】:

    考虑使用 HTML 解析库而不是正则表达式,例如 simplehtmldom。您可以使用它来更新特定 HTML 标签的内容(因此,忽略您不想更改的标签)。那时您不必使用正则表达式;过滤适当的标签后,只需使用 str_replace 之类的函数即可。

    【讨论】:

      【解决方案4】:
      $lines = explode( "\n", $content );
      $lines[0] = stri_replace( "keyword", "replacement", $lines[0] );
      $content = implode( "\n", $lines );
      

      或者如果你明确想要使用正则表达式

      $lines = explode( "\n", $content );
      $lines[0] = preg_replace( "/keyword/i", "replacement", $lines[0] );
      $content = implode( "\n", $lines );
      

      【讨论】:

      • 那些直接替换替换所有出现的“关键字”。我只是想替换其中的一些。不过还是谢谢
      猜你喜欢
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      相关资源
      最近更新 更多