用递归和正则表达式替换字符串中的文本

在浏览器中显示输出之前,我使用标签来替换文本,类似于 Wordpress 的短代码。

示例字符串: Hi, this is a block of text {{block:welcome}} and this is a system variable {{variable:system_version}}

我有相应的函数来替换这些块,并且我意识到 foreach 或 while 函数将是处理它的最佳方法,但不幸的是,替换一个{{...}}可能会引入另一个。因此,我选择递归,直到找不到更多。典型的递归只有一次,但我有两个合二为一的场景。也许调用该函数 3 次会起作用,但听起来“错误”。

现在这就是问题发生的地方:我不想在它们出现时更换它们:

1) A page where the URL you are calling contains something
2) Any form element such as `<input>` or `<textarea>`.

我需要关于如何通过正则表达式从上面的 #2 中排除的帮助。

我的正则表达式目前看起来像这样:(^\{\{((?!keep).)*$我意识到它可能仍然是错误的,或者需要修改 - 还不太有效)。

如果项目包含“保持”,例如,{{block:welcome:keep}}它不应该被替换,但是当这样做时,递归永远不会停止,因为我一直在寻找要替换的项目,从而耗尽内存,或者获得最大的嵌套级别错误。

我之所以要这样做,是因为我不希望在 ADMIN 页面上或在编辑表单内容时替换内容。

有人愿意给它一个裂缝吗?如果这很重要,我正在使用 PHP。

谢谢!

编辑 1

由于@Pablo 的答案是在聊天中给我的,我决定编辑我的问题以反映为什么他的答案被标记为正确的答案。

我的正则表达式现在看起来像这样: /(?:<(?:textarea|select)[\s\S]*?>[\s\S]*?)?({{variable:(.*?)}})[\s\S]*?(?:<\/(?:textarea|select)>)?|(?:<(?:input)[\s\S]*?)?{{variable:(.*?)}}(?:[\s\S]*?>)?/im

然后我检查匹配项是否包含输入、选择或文本区域,如果是,则{{暂时用其他内容替换,然后进行替换,完成后,将“其他内容”更改回{{Pablo 建议的内容。我的正则表达式要感谢这个问题的答案:文本替换:PHP/regex

如果以上编辑不属于,请随意删除。


互换的青春
浏览 126回答 1
1回答

海绵宝宝撒

我建议不要寻找完美的 RegEx,而是考虑使用preg_replace_callback()。它应该允许您使用更简单的 RegEx,同时更好地控制模板引擎的搜索和替换算法。考虑以下示例:resolvePlaceholder()&nbsp;生成替换内容interpolate()解析模板字符串。它支持多达 4 级的嵌套解析。停止递归解析以 开头的标签!。<?phpfunction resolvePlaceholder($name){&nbsp; &nbsp; $store = [&nbsp; &nbsp; &nbsp; &nbsp; 'user:first'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => 'John',&nbsp; &nbsp; &nbsp; &nbsp; 'user:last'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=> 'Doe',&nbsp; &nbsp; &nbsp; &nbsp; 'user:full_name'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => '{{user:first}} {{user:last}}',&nbsp; &nbsp; &nbsp; &nbsp; 'block:welcome'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=> 'Welcome {{user:full_name}}',&nbsp; &nbsp; &nbsp; &nbsp; 'variable:system_version' => '2019.1',&nbsp; &nbsp; &nbsp; &nbsp; 'nest-test'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=> '{{level1}}',&nbsp; &nbsp; &nbsp; &nbsp; 'level1'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => '{{level2}}',&nbsp; &nbsp; &nbsp; &nbsp; 'level2'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => '{{level3}}',&nbsp; &nbsp; &nbsp; &nbsp; 'level3'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => '{{level4}}',&nbsp; &nbsp; &nbsp; &nbsp; 'level4'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => '{{level5}}',&nbsp; &nbsp; &nbsp; &nbsp; 'level5'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; => 'Nesting Limit Test Failed',&nbsp; &nbsp; &nbsp; &nbsp; 'user-template'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=> 'This is a user template with {{weird-placeholder}} that will not be replaced in edit mode {{user:first}}',&nbsp; &nbsp; ];&nbsp; &nbsp; return $store[$name] ?? '';}function interpolate($text, $level = 1){&nbsp; &nbsp; // Limit interpolation recursion&nbsp; &nbsp; if ($level > 5) {&nbsp; &nbsp; &nbsp; &nbsp; return $text;&nbsp; &nbsp; }&nbsp; &nbsp; // Replace placeholders&nbsp; &nbsp; return preg_replace_callback('/{{([^}]*)}}/', function ($match) use ($level) {&nbsp; &nbsp; &nbsp; &nbsp; list($tag, $name) = $match;&nbsp; &nbsp; &nbsp; &nbsp; // Do not replace tags with :keep&nbsp; &nbsp; &nbsp; &nbsp; if (strpos($name, ':keep')) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Remove :keep?&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return $tag;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (strpos($name, '!') === 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return resolvePlaceholder(trim($name, '!'));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return interpolate(resolvePlaceholder($name), $level + 1);&nbsp; &nbsp; }, $text);}$sample = 'Hi, this is a block of text {{block:welcome}} and this is a system variable {{variable:system_version}}. ' .&nbsp; &nbsp; 'This is a placeholder {{variable:web_url:keep}}. Nest value test {{nest-test}}. User Template: {{!user-template}}';echo interpolate($sample);// Hi, this is a block of text Welcome John Doe and this is a system variable 2019.1. This is a placeholder {{variable:web_url:keep}}. Nest value test {{level5}}. User Template: This is a user template with {{weird-placeholder}} that will not be replaced in edit mode {{user:first}}
打开App,查看更多内容
随时随地看视频慕课网APP