正则表达式替换非标签(非HTML)包含的单词

3

我的正则表达式经验有限,我正在使用 PHP 中的 preg_replace 函数。

我想要替换一个指定的“单词”,该单词不在 [no-glossary]...[/no-glossary] 标签之间。如果单词和标签之间没有空格,或者单词后面有一个空格,那么我的表达式可以工作,但是如果我在单词前放一个空格(预期的情况),它将失败!

下面的例子有效:

$html = '<p>Do not replace [no-glossary]this[/no-glossary] replace this.</p>';
$html = '<p>Do not replace [no-glossary]this [/no-glossary] replace this.</p>';

这不行:
$html = '<p>Do not replace [no-glossary] this [/no-glossary] replace this.</p>';

逐部分解释所使用的模式

/                      - find
(?<!\[no-glossary\])   - Not after the [no-glossary] tag
[ ]*                   - Followed by 0 or more spaces (I think this is the problem)
\b(this)\b             - The word "this" between word boundaries
[ ]*                   - Followed by 0 or more spaces
(?!\[\/no-glossary\])  - Not before the [/no-glossary] tag
/

这里是代码:

$pattern = "/(?<!\[no-glossary\])[ ]*\b(this)\b[ ]*(?!\[\/no-glossary\])/"; 
$html = '<p>Do not replace [no-glossary] this [/no-glossary] replace this.</p>';
$html = preg_replace($pattern, "that", $html);

print $html;

输出:

<p>Do not change [no-glossary] that [/no-glossary] changethat.</p>

问题:

  1. 标签之间的单词被更改。
  2. 第二个单词前面的空格被移除,而它本应该被替换。

1
感谢您为我编辑这个 Brad。 - user2254788
5个回答

3
只捕获空格:
$subject = <<<LOD
<p>Do not replace [no-glossary]this[/no-glossary] replace this.</p>
<p>Do not replace [no-glossary]this [/no-glossary] replace this.</p>
<p>Do not replace [no-glossary] this[/no-glossary] replace this.</p>
<p>Do not replace [no-glossary] this [/no-glossary] replace this.</p>
LOD;
$pattern = '`(?<!\[no-glossary])( *+)\bthis\b( *+)(?!\[/no-glossary])`';
echo $subject.'<br/>';
echo preg_replace($pattern,"$1rabbit$2",$subject); ?>

哇,你一定是个天才!!我以为$1和$2是打错了,但它确实有效。这些是目标单词前后的空格的占位符吗? - user2254788
@user2254788 是的,$1和$2分别是第一组和第二组捕获的内容,它们匹配空格(*+)。 - Casimir et Hippolyte
如果出现 Do not replace this[/no-glossary] replace this. 或者 Do not replace [no-glossary]this replace this.,这段代码将无法正常工作。@user2254788 如果不影响的话,请使用这个解决方案! - HamZa
还有一个快速(最后)的问题。模式中的重音符号(`)是用来做什么的? - user2254788
@user2254788 没有使用 / 作为分隔符,而是使用了 \``,实际上你也可以使用 #~` 等作为分隔符! - HamZa

3

在尝试使用正则表达式模式后,我发现Regex PCRE引擎有一些限制,因此我从另一个角度解决了这个问题:

  1. 匹配所有的 [no-glossary] this [/no-glossary]this
  2. 筛选结果。

可以使用 preg_replace_callback() 来完成:

需要 PHP 5.3+ 版本

$pattern = "/\[no-glossary\][ ]*\bthis\b[ ]*\[\/no-glossary\]|this/"; 
$html = '<p>Do not replace [no-glossary] this [/no-glossary] replace this.</p>';

$html = preg_replace_callback($pattern, function($match){
    if($match[0] == 'this'){
        return('that');
    }else{
        return($match[0]);
    }
}, $html);

print $html;

如果你没有运行 PHP 5.3+ :

$pattern = "/\[no-glossary\][ ]*\bthis\b[ ]*\[\/no-glossary\]|this/"; 
$html = '<p>Do not replace [no-glossary] this [/no-glossary] replace this.</p>';

$html = preg_replace_callback($pattern, 'replace_function', $html);

function replace_function($match){
    if($match[0] == 'this'){
        return('that');
    }else{
        return($match[0]);
    }
}
print $html;

动态:

$tag = 'no-glossary';
$find = 'this';
$replace = 'that';

$pattern = "/\[$tag\][ ]*\b$find\b[ ]*\[\/$tag\]|$find/"; 
$html = '<p>Do not replace [no-glossary] this [/no-glossary] replace this.</p>';

$html = preg_replace_callback($pattern, function($match) use($find, $replace){
    if($match[0] == $find){
        return($replace);
    }else{
        return($match[0]);
    }
}, $html);

print $html;

以下是有关编程的内容,请将其从英语翻译成中文。仅返回翻译文本:注:此方法无法用于<p>不要替换 [no-glossary] lol this [/no-glossary] 替换这个。</p> - HamZa
Hamza,这个很好。现在我有两个解决方案。您能否对上面的@Casimir-et-Hippolyte解决方案进行评论?哪个更快? - user2254788

1

尝试这个:([^\[\]])this([^\[\]])

当然,你需要将其应用于实际需要的“this”单词。


谢谢,但这导致了与上述相同的问题。请注意,当单词“this”前后有空格时(例如“ this ”),问题会出现。 - user2254788

0

尝试这个,它只替换this这个单词

$pattern = '%([^\da-zA-Z]+)this([^\da-zA-Z]+)%si';
$html = '<p>Do not replace [no-glossary]this sdf[/no-glossary] thisreplace<p> replacethis.</p>replace this.</p>';
function Replace1($M){
//print_r($M);
    return $M[1]."that".$M[2];
}
$html = preg_replace_callback($pattern,"Replace1",$html);
print $html;

输出:

<p>Do not replace [no-glossary]that sdf[/no-glossary] thisreplace<p> replacethis.</p>replace that.</p>

这与 OP 想要的相反。他不想替换 [no-glossary][/no-glossary] 之间的内容。 - HamZa
谢谢,Mohammad,但是它替换了错误的实例!你能尝试一下将单词 NOT 替换为 [no-glossary] 标签之外的表达式吗? - user2254788
@hamza-dzcyberdev 你明白了吗?有解决方案吗? - user2254788
@user2254788 是的,我仍在思考,我想到了一个解决方案,但似乎 PCRE 正则表达式引擎不支持它!所以我正在钻研一个变通方法! - HamZa
@user2254788,请查看答案更改。 - mohammad mohsenipur

0

试试这个:

\b(this)\b(?!(?:(?!\[no-glossary\]).)*?\[/no-glossary\])

如果遇到[no-glossary],则排除替换后面跟着[/no-glossary]this


这对于<p>不要替换这个[/no-glossary]替换这个。</p>是行不通的。 - HamZa
嗨,马塞卢斯。这个模式导致了一个错误:警告:preg_replace() [function.preg-replace]:在eval()(/var/www/html/websites/sites/all/modules/contrib/devel/devel.module(1285) : eval()'d code)的第6行中未知修饰符“n”。你能重新检查一下语法吗? - user2254788
@user2254788 他忘记转义正斜杠了:\b(this)\b(?!(?:(?!\[no-glossary\]).)*?\[\/no-glossary\]) - HamZa

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