【问题标题】:Regular expression to replace words in web pages正则表达式替换网页中的单词
【发布时间】:2013-05-07 10:50:58
【问题描述】:

我正在寻找一个正则表达式 (php) 来查找/替换网页中的某些单词。但是,它不能替换所有html标签之间的单词,只能在:斜体i>、粗体b>和纯文本之间。

示例:

单词:“hello”(不区分大小写)

<a href="#">Hello</a> im a writer that i like to say hello everyday. <b>Hello</b> Spiderman.

替换:在anchor cant replace中,只能替换hello和&lt; b&gt;Hello&lt; /b&gt;

我测试了一些正则表达式,但没有一个能正常工作:

1) 来自 SMART SEO LINKS(WP 插件)

$reg = '/(?!(?:[^<\[]+[>\]]|[^>\]]+<\/a>))\b($word)\b/Imsu';

效果不好,有时,删除内容并放上simbol ">" 我对这个正则表达式做了一些修改,去掉了“?!”或“?:”(我不知道是什么意思),但停止工作。

2) 我尝试过的其他人:

$reg = "/<([\w]+)[^>]*>\b('.$word.')\b<\/\1>/Imsu";
$reg = '/<+\s*\/\s\b('.$word.')\b[^>]\/\s>+/I';

不替换任何东西

$reg = '/<(\w+)[^>]*>\b('.$name.')\b<\/\1>/Imsu';

有时有效。

事实是我不是正则表达式专家,我进行了几天的测试,试图创建一个新的正则表达式,但没有达到我需要的结果。

事实上,替换将在 WP 插件中使用,这有时会影响模板或其他插件或 DOM 没有很好地创建

有人知道为什么不能正常工作吗?谢谢。

【问题讨论】:

标签: php regex wordpress html-parsing preg-replace


【解决方案1】:

尝试这些模式的组合

$reg = '/(?:<(\w+)[^>]*>)?\bhello\b(?!<\/a>)(<\/\\1>)?/i';
$reg0 = '/<\w[^>]*\bhello\b[^>]*>/Ui';

示例

$word = preg_quote('hello','/'); // to avoid PCRE injection
$str = '<a href="hello.php">Hello</a> I say hello everyday. <b>Hello</b> Spiderman.';
$reg = '/(?:<(\w+)[^>]*>)?\b'.$word.'\b(?!<\/a>)(<\/\\1>)?/i';
$reg0 = '/<\w[^>]*\b'.$word.'\b[^>]*>/Ui';

function handler($m) { return str_replace($GLOBALS["word"],'!X!',$m[0]); }

$str = preg_replace_callback($reg0,'handler',$str); // replace "hello" for say !X! inside tags    
$str = preg_replace($reg,'[deleted]',$str); // delete "hello" elsewhere
$str = str_replace('!X!',$word,$str); // put "hello" inside tag back
print_r($str);

结果

<a href="hello.php">Hello</a> I say [deleted] everyday. [deleted] Spiderman.

问题注释

说明

参见上面关于断言的链接:?&lt;! 否定后向断言不能用于匹配&lt;a href="#"&gt;,因为它不是固定长度并导致编译错误。因此我在你好之后使用了前瞻断言?! 来匹配&lt;/a&gt;。开头和结尾的括号包括任何周围的 HTML 标记,因此除了 &lt;/a&gt; 断言之外的所有内容都将被替换。

避免标签内 hello 替换的技巧是将它们替换为一些唯一的字符串(例如 !X!),然后进行原始替换,然后将 !X! 替换回 hello 回来。这可能不是最好的解决方案,但它确实有效。

为什么您的正则表达式不起作用

您使用了/I 修饰符(在模式的末尾)。修饰符区分大小写,/i 表示不区分大小写,参见the list of modifiers。我相信您的模式中的\b(单词边界)是多余的。

【讨论】:

  • 那行得通,但它并不是我真正想要的。这个想法只替换:(1)纯文本或标签之间的文本(2)text或(3)text你的正则表达式替换锚内的文本:不能替换的文本 我正在查看的结果应该是这样的:&lt;a href="#"&gt;Hello&lt;/a&gt; im a writer that i like to say [deleted] everyday.
  • @JuanVargasZuljin:我明白了。我已经更新了我的答案 - 现在可以用了吗?
  • 再次感谢。我正在测试它,但是当出现$str = "&lt;a href='http://www.hello.com'&gt;Hello&lt;/a&gt; I say hello everyday. &lt;b&gt;Hello&lt;/b&gt; Spiderman."; 这样的情况时,结果将是&lt;a href='http://www.[deleted].com'&gt;Hello&lt;/a&gt; I say [deleted] everyday. [deleted] Spiderman. 如您所见,在“href”中也进行了替换,并确保在 上的其他属性中进行替换,这可能很危险。你有什么想法 ?太难解决了?
  • @JuanVargasZuljin:够难,但仍然可以解决。请参阅我的更新和解释中的第二段。
  • 正确。只需添加文档中所写的负前瞻序列(?!&lt;\/tag1&gt;)(?!&lt;\/tag2&gt;)。我正在使用您的 \b 建议更新我的答案,以帮助其他人浏览此问题。
猜你喜欢
  • 2022-12-10
  • 2020-01-06
  • 1970-01-01
  • 2015-09-03
  • 2019-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多