用于术语表替换的正则表达式

时间:2012-04-01 06:01:59

标签: php regex preg-replace

我正在编写词汇表模块 - 它必须在文本中找到已知单词并通过链接替换它。如果它是链接ancor(<a href="...">word</a>)或属性(<span class="word">...</span>),则不得替换word。

我写了代码:

$x = '<div>DVB-S2. DVB-S. DVB-S2DVB-S <sss DVB-S2 /> DVB-S2 <a href="dd">DVB-S2</a> DVB-S2 Hot bird 6/Hot Bird 8/Hot bird 9, 13.0</div>';

$word = 'Hot Bird 8';
$x = preg_replace("'(?<=[\s\>])(" . $word . ")(?=[^\d\w\-])(?!([^<]+)?>)'is", "<a href=\"s2\">$1</a>", $x);

$word = 'DVB-S2';
$x = preg_replace("'(?<=[\s\>])(" . $word . ")(?=[^\d\w\-])(?!([^<]+)?>)'is", "<a href=\"s2\">$1</a>", $x);

echo $x;

但它将<a href="dd">DVB-S2</a>替换为<a href="dd"><a href="s2">DVB-S2</a></a>

我该如何解决?

2 个答案:

答案 0 :(得分:0)

你需要将其分解为三个规则:

  1. Word的双边由非单词字符或BO [SL] / EO [SL]分隔。
  2. Word不在&lt;之间。及其匹配&gt;。
  3. Word不介于和之间。
  4. 对于规则(1),我们需要一个积极的前瞻和后视:

    (?<=^|\W)word(?=\W|$)
    

    \W捕获非单词字符,除了字母,数字和下划线之外的其他内容。这与您的版本不完全相同,但您可以根据需要进行调整。 \b也可能是个不错的选择,在这种情况下你不需要插入符号和美元符号。

    现在,为规则(2)添加负面的lookbehind:

    (?<!<[^>]*)(?<=^|\W)(DVB-S2)(?=\W|$)
    

    当单词前面有<和任何非>字符时,即当它位于任何HTML标记的中间时,这会阻止匹配。

    现在,为规则(3)添加否定前瞻:

    (?<!<[^>]*)(?<=^|\W)(DVB-S2)(?=\W|$)(?!</a>)
    

    这可以防止匹配单词后立即后跟</a>。这不是一个完美的解决方案,因为该单词可能不是链接文本的唯一部分,但它可能足够接近您的情况,并且它通过您的测试用例。在单个表达式中可能有一种比这更精确的方法,但目前没有任何想法。

    以上所有内容都是用.NET-dialect正则表达式编写的,我假设PHP足够相似,可以为你工作。

答案 1 :(得分:0)

这是我得到的,我希望它有效

   echo preg_replace("@((?!<a\s*[^<>]*>.*?))($word)((?!</a>.))@i",'$1<a href="">$2</a>$3',$html) . chr(10);

将输出

<div><a href="">DVB-S2</a>. DVB-S. <a href="">DVB-S2</a>DVB-S <sss <a href="">DVB-S2</a> /> <a href="">DVB-S2</a> <a href="dd">DVB-S2</a> <a href="">DVB-S2</a> Hot bird 6/Hot Bird 8/Hot bird 9, 13.0</div>