使用REGEX匹配字符串,而不在字符串中重复第一个标记。 (第2部分)

时间:2012-07-04 01:21:08

标签: perl

感谢@ cool_me5000在这里帮助我解决了这个问题的过度简化版本:PERL: Using REGEX to match a string without the first token repeated in the string. (ABC, not AAA ABC)

以下是经过调整的问题:

我正在尝试使用正则表达式匹配第一个实例,其中ATE跟随CAT而ATE和CAT之间没有另一个ATE。我想要匹配“ATE BAT CAT”。请注意,在此文本字符串中,第一个ATE / CAT组合之后还有其他实例也可以适合ATE / CAT,(特别注意“字符串末尾附近的ATE DOG CAT”)以下是文本:

$TEXT = "ATE ATE ATE ATE BAT CAT ATE DOG EGG ATE FOR GIN ATE DOG CAT ATE";

我第一次尝试:

@finds1=$TEXT=~m/((ATE).*?(CAT))/;
$result = $finds1[0];
print "result = $result\n";

这将打印以下内容:

result = ATE ATE ATE ATE BAT CAT

当我想要的只是:

result = ATE BAT CAT

请注意,我正在尝试创建一个可以在B可以是任何字符串的情况下使用的正则表达式。例如ATE DOG CAT,ATE FAT GET HAT JOT KIN CAT,ATE YAK ULE INN OLD KOC JOG HUG GOT TAL CAT。

我接下来尝试使用look-forward结合if then else语句。这是代码:

@finds1=$TEXT=~m/(ATE(?(?!.*?ATE.*?CAT).*?CAT|Z{100}))/;
$result = $finds1[0];
print "result = $result\n";

REGEX的第一部分,(ATE,告诉perl找到ATE的出现。一旦找到,perl然后处理if then else语句,其中条件语句是没有实例。?ATE 。?CAT跟随ATE,如果没有找到,那么perl会查找。*?CAT,如果找到至少一个,那么它会搜索100个Z实例。(我的方式是让Perl继续前进既不是在本文中也不是在我试图解析的文本中都有100个Z.)

返回:

result = ATE DOG CAT    

在第一次识别CAT后,我考虑过使用正面的后视镜。但是,正如我上面提到的,它们之间没有A的第一个ATE.CAT组合之间的字符数是可变的。据我所知,PERL不能做可变长度的后视镜。

您可以提供的任何帮助或指示都会非常感激!!

提前致谢!

1 个答案:

答案 0 :(得分:3)

对于之前的问题,解决方案是:

my ($first) = $text =~ /(A[^AC]*C)/;

我们使用了A|C的否定,这意味着我们需要在这里使用ATE|CAT的否定。

每个人都应该知道的是(?:(?!STRING).)(?:STRING)[^CHAR]CHAR(?:(?!PAT).)也适用于一些更复杂的模式,包括上面的模式。

所以我们得到:

my ($first) = $text =~ /(ATE (?:(?!ATE|CAT).)* CAT)/sx;

说明:

你不希望“ATE”和“CAT”之间有“CAT”或“ATE”,所以

   +---------------- You don't want CAT or ATE starting here.
   |+--------------- You don't want CAT or ATE starting here.
   ||--+------------ You don't want CAT or ATE starting here.
   ||   +----------- You don't want CAT or ATE starting here.
   ||   |+---------- You don't want CAT or ATE starting here.
   ||   ||
   vv   vv
ATE??...??CAT

那就是

/
   ATE
   (?! CAT|ATE ) .
   (?! CAT|ATE ) .
   ...
   (?! CAT|ATE ) .
   (?! CAT|ATE ) .
   CAT
/x

使用*处理重复。