最短的匹配问题

Eri*_*ert 1 regex perl

我知道吗?操作员启用"非贪婪"模式,但我遇到了问题,我似乎无法绕过.考虑这样的字符串:

my $str = '<a>sdkhfdfojABCasjklhd</a><a>klashsdjDEFasl;jjf</a><a>askldhsfGHIasfklhss</a>';
Run Code Online (Sandbox Code Playgroud)

那里有开始和结束标记<a>,并</a>有键ABC,DEF和GHI,但其他一些随机文本包围.我想更换<a>klashsdjDEFasl;jjf</a><b>TEST</b>的例子.但是,如果我有这样的事情:

$str =~ s/<a>.*?DEF.*?<\/a>/<b>TEST><\/b>/;
Run Code Online (Sandbox Code Playgroud)

即使有非贪婪的操作员.*?,这也不能满足我的需要.我知道它为什么不这样做,因为第一个<a>匹配字符串中的第一个匹配,并且一直匹配到DEF,然后匹配到最近的结束</a>.然而,我想要的是一种方法来匹配最接近的开启<a>和关闭</a>"DEF".所以目前,我得到了这个结果:

<a>TEST</b><a>askldhsfGHIasfklhss</a>
Run Code Online (Sandbox Code Playgroud)

我在哪里寻找能得到这个结果的东西:

<a>sdkhfdfojABCasjklhd</a><b>TEST</b><a>askldhsfGHIasfklhss</a>
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我不是想在这里解析HTML,我知道有这样的模块,我只想问一下如何做到这一点.

谢谢,Eric Seifert

cjm*_*cjm 6

$str =~ s/(.*)<a>.*?DEF.*?<\/a>/$1<b>TEST><\/b>/;
Run Code Online (Sandbox Code Playgroud)

问题是即使使用非贪婪的匹配,Perl仍然试图找到从字符串中最左边可能点开始的匹配.由于.*?可以匹配<a>或者</a>,这意味着它总能找到第一个<a>就行了.

(.*)在开头添加一个贪婪使它找到该行的最后一个匹配<a>(因为.*首先抓住整行,然后回溯直到找到匹配).

一个警告:因为它首先找到最右边的匹配,所以不能将此技术用于/g修饰符.任何其他匹配将在内部$1,并/g恢复上一个匹配结束的搜索,因此它将找不到它们.相反,你必须使用如下循环:

1 while $str =~ s/(.*)<a>.*?DEF.*?<\/a>/$1<b>TEST><\/b>/;
Run Code Online (Sandbox Code Playgroud)