2

我试图匹配可能在字符串中找到的几个单词中的第一个和最后一个字母。我正在使用带有|.

让我们采用以下字符串:

The quick brown fox jumps over the lazy dog

我想匹配foxor dog,所以我做了以下正则表达式:

/fox|dog/

使用 PHP 的preg_replace,该正则表达式可以正常工作:

$str = 'The quick brown fox jumps over the lazy dog';
echo preg_replace('/fox|dog/', '=>$0<=', $str);

这呼应:

The quick brown =>fox<= jumps over the lazy =>dog<=

这不是我想要的结果。因此,从该正则表达式开始,我尝试对其进行修改,以使结果如下所示:

The quick brown =>f...x<= jumps over the lazy =>d...g<=

我试过这段代码:

$str = 'The quick brown fox jumps over the lazy dog';
echo preg_replace('/(f)o(x)|(d)o(g)/', '=>$1...$2<=', $str);

这没有产生我想要的。这呼应了:

The quick brown =>f...x<= jumps over the lazy =>...<=

经过一番调试,我弄清楚了原因。我想,因为我使用|它会分别匹配每个单词,但事实并非如此。正如我所想的那样f是反向引用1,但d不是。d实际上是反向引用3!这是因为这些组是针对整个正则表达式的,而不仅仅是|匹配的哪一侧。但是,反向引用0总是匹配的词(或),所以有点困惑。foxdog

如何使用反向引用来匹配多个单词的第一个和最后一个字母?

我找到了使用 的解决方案preg_replace_callback,但我想知道是否可以使用反向引用获得相同的结果。

$str = 'The quick brown fox jumps over the lazy dog';
echo preg_replace_callback('/fox|dog/', function($matches){
    $a = $matches[0];
    return '=>'.$a[0].'...'.$a[strlen($a)-1].'<=';
}, $str);
4

2 回答 2

2

我可以为此使用不匹配的前瞻表达式:

/(?=fox|dog)(f|d)o(x|g)/

(未在 PHP 中测试,但在 JS 中有效)

它首先测试以下是否是搜索到的单词之一,然后仅匹配一个捕获组中的第一个和最后一个字母。但是,如果单词不那么相似(这里:相同的长度,相同的中间字母[s]),此方法将变得更加复杂。

于 2013-01-30T18:35:38.427 回答
2

实际上回调函数方法优于这一切,因为它可以在所有情况下工作。您甚至可以根据匹配的长度显示更多或更少的字符。


以下是我最初的回答,不如我上面描述的

一般来说,你可以这样做:

/(?=(.))(?:pattern)(?<=(.))/s

填写pattern你的图案。我使用s标志来.真正匹配任何字符,无一例外。如果原始模式没有在最高级别,则不需要pattern非捕获组内。|

不过,在进行替换之前,您仍然需要检查模式捕获的文本的长度。(特别是长度为 1 的情况,也可能为 2)。这很容易通过使用替换回调函数来实现。

但是,请注意,上述方法可能不适用于最小长度为 0 的模式。

于 2013-01-30T18:41:48.557 回答