首页 > 解决方案 > PHP 正则表达式替换没有产生预期的结果

问题描述

我正在 PHP 和 MariaDB 中创建一个字典应用程序,并尝试模拟一些基本的降价。当我有这样的定义时:

This is an example definition. Here is a link to [foo]. This is an [aliased link|bar].

然后[foo]会被翻译成'foo'定义页面[aliased link|bar]的链接,并且会被翻译成'bar'定义页面的链接。如果有管道,那么管道 (|) 之前的任何内容都将成为链接文本,而管道之后的内容将成为链接目标。如果没有管道,则括号中的表达式将成为链接文本和目标。

所以我会把它翻译成下面的 HTML:

This is an example definition. Here is a link to <a href="foo">foo</a>. This is an <a href="bar">aliased link</a>.

我能想到的最简单的方法是通过两个正则表达式替换。因此,假设我的示例字符串被调用$def,这是我尝试进行这些替换的代码:

$pattern1 = '/\[(.*?)?\]/m';
$replace1 = '<a href="$1">$1</a>';
$def = preg_replace($pattern1, $replace1, $def);

$pattern2 = '/\[([^]]*?)(?:\|([^]]*?))\]/m';
$replace2 = '<a href="$2">$1</a>';
$def = preg_replace($pattern2, $replace2, $def);

(我认为使用两个正则表达式会更容易,但如果有更简单的一个正则表达式解决方案,我很想知道。)

但是,我显然对正则表达式有问题,因为这是我回显时发生的情况$def(链接现在只是说明性的,目的地并不重要):

这是一个示例定义。这是foo的链接。这是一个别名link|bar

和 HTML:

"This is an example definition. Here is a link to "
<a href="foo">foo</a>
". This is an" 
<a href="aliased link|bar">aliased link|bar</a>
"."

谁能建议我需要做些什么来修复正则表达式以获得我想要的结果?我特别困惑,因为当我在www.regex101.com测试这个正则表达式时,它似乎完全按照我的想法做:

在此处输入图像描述

我在 Google Chrome 上使用 PHP 7.4.6,带有 XAMPP 和 Apache。

标签: phphtmlregexpreg-replace

解决方案


Note that in the pattern that you used, you can exclude matching the | by adding it in the first negated character class to prevent some backtracking. The quantifier for the negated character class also does not have to be non greedy *? as the ] can not be crossed at the end.

You could use 2 capture groups where the second group is in an optional part and check for the presence of group 2 using preg_replace_callback.

\[([^][|]+)(?:\|([^][]+))?]

The pattern matches:

  • \[ Match [
  • ([^][|]+) Capture group 1, match 1+ times any char except [ ] and |
  • (?:\|([^][]+))? Optional non capture group matching | and capture any char except the listed in group 2
  • ] Match closing ]

Regex demo | Php demo

$pattern = "/\[([^][|]+)(?:\|([^][]+))?\]/";
$s = "This is an example definition. Here is a link to [foo]. This is an [aliased link|bar].";
$s = preg_replace_callback($pattern, function($match){
    $template = '<a href="%s">%s</a>';
    return sprintf($template, array_key_exists(2, $match) ? $match[2] : $match[1], $match[1]);
}, $s);

echo $s;

Output

This is an example definition. Here is a link to <a href="foo">foo</a>. This is an <a href="bar">aliased link</a>.

推荐阅读