PHP 正则表达式替换没有产生预期的结果
PHP Regex replace is not producing the desired result
我正在 PHP 和 MariaDB 中创建字典应用程序,并尝试模拟一些基本的降价。当我有这样的定义时:
This is an example definition. Here is a link to [foo]. This is an [aliased link|bar].
然后[foo]
会翻译成link到'foo'定义页,[aliased link|bar]
会翻译成link到'bar'定义页。如果有管道,则管道 (|) 之前的任何内容都将成为 link 文本,而管道之后的内容将成为 link 目标。如果没有竖线,则括号中的表达式成为 link 文本和目标。
所以我会把它翻译成下面的 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=""></a>';
$def = preg_replace($pattern1, $replace1, $def);
$pattern2 = '/\[([^]]*?)(?:\|([^]]*?))\]/m';
$replace2 = '<a href=""></a>';
$def = preg_replace($pattern2, $replace2, $def);
(我假设使用两个正则表达式会更容易,但如果有更简单的一个正则表达式解决方案我很想知道。)
但是,我的正则表达式显然有问题,因为当我回显 $def
时会发生这种情况(link 目前只是说明性的,目标不是重要):
This is an example definition. Here is a link to foo. This is an aliased 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。
请注意,在您使用的模式中,您可以通过将 |
添加到第一个否定字符 class 中来排除匹配,以防止某些回溯。否定字符的量词 class 也不必非贪婪 *?
因为 ]
不能在最后交叉。
您可以使用 2 个捕获组,其中第二个组位于可选部分,并使用 preg_replace_callback 检查是否存在第 2 组。
\[([^][|]+)(?:\|([^][]+))?]
模式匹配:
\[
匹配 [
([^][|]+)
捕获 组 1,匹配任何字符 1+ 次,除了 [
]
和 |
(?:\|([^][]+))?
可选非捕获组匹配 |
并捕获除 group 2 中列出的任何字符
]
比赛结束 ]
$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;
输出
This is an example definition. Here is a link to <a href="foo">foo</a>. This is an <a href="bar">aliased link</a>.
我正在 PHP 和 MariaDB 中创建字典应用程序,并尝试模拟一些基本的降价。当我有这样的定义时:
This is an example definition. Here is a link to [foo]. This is an [aliased link|bar].
然后[foo]
会翻译成link到'foo'定义页,[aliased link|bar]
会翻译成link到'bar'定义页。如果有管道,则管道 (|) 之前的任何内容都将成为 link 文本,而管道之后的内容将成为 link 目标。如果没有竖线,则括号中的表达式成为 link 文本和目标。
所以我会把它翻译成下面的 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=""></a>';
$def = preg_replace($pattern1, $replace1, $def);
$pattern2 = '/\[([^]]*?)(?:\|([^]]*?))\]/m';
$replace2 = '<a href=""></a>';
$def = preg_replace($pattern2, $replace2, $def);
(我假设使用两个正则表达式会更容易,但如果有更简单的一个正则表达式解决方案我很想知道。)
但是,我的正则表达式显然有问题,因为当我回显 $def
时会发生这种情况(link 目前只是说明性的,目标不是重要):
This is an example definition. Here is a link to foo. This is an aliased 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。
请注意,在您使用的模式中,您可以通过将 |
添加到第一个否定字符 class 中来排除匹配,以防止某些回溯。否定字符的量词 class 也不必非贪婪 *?
因为 ]
不能在最后交叉。
您可以使用 2 个捕获组,其中第二个组位于可选部分,并使用 preg_replace_callback 检查是否存在第 2 组。
\[([^][|]+)(?:\|([^][]+))?]
模式匹配:
\[
匹配[
([^][|]+)
捕获 组 1,匹配任何字符 1+ 次,除了[
]
和|
(?:\|([^][]+))?
可选非捕获组匹配|
并捕获除 group 2 中列出的任何字符
]
比赛结束]
$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;
输出
This is an example definition. Here is a link to <a href="foo">foo</a>. This is an <a href="bar">aliased link</a>.