感谢@ 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不能做可变长度的后视镜。
您可以提供的任何帮助或指示都会非常感激!!
提前致谢!
答案 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
使用*
处理重复。