我重構了你的代碼,使其更容易直觀地看到發生了什麼。
my $regex = qr/
M? # 1: Match M, greedy, 0 or 1 times.
[VI]? # 2: Match V or I, greedy, 0 or 1 times.
A? # 3: Match A, greedy, 0 or 1 times.
R? # 4: Match R, greedy, 0 or 1 times.
G? # 5: Match G, greedy, 0 or 1 times.
D? # 6: Match D, greedy, 0 or 1 times.
[LM]? # 7: Match L or M, greedy, 0 or 1 times.
G? # 8: Match G, greedy, 0 or 1 times.
[IVMAL]? # 9: Match I, B, M, A or L, greedy, 0 or 1 times.
E? # 10: Match E, greedy, 0 or 1 times.
/x;
my $text = "VMVARGDLGVE";
if (my @matched = $text =~ /$regex/gx) {
print "No of matches: ", scalar(@matched), "\n";
print "<<$_>>\n" foreach @matched;
}
您的正則表達式在儘可能多的方式上匹配,而不會破壞其NFA正則表達式引擎的規則。
這些規則之一是「最左邊的」。將選擇最接近目標中左側 的子串,以允許總匹配成功。
的另一條規則是,貪婪的量詞將匹配儘可能 可能的,只會給了他們所擁有的子匹配,如果有必要,讓全場比賽成功 。放棄部分 他們的比賽涉及回溯。除非量詞太多,否則迴避將被避免,並且必須放棄以允許完整匹配成功。
而另一個規則是,迭代匹配在點 處繼續前一場比賽中止。
透過目標串散步, 「V」 的子模式[VI]?
(下文中被稱爲子模式#2)相匹配。貪婪的量詞持有這個'V',並且只有當它被強制在後面時纔會釋放它,以獲得更大的好處。
目標字符串中的「M」與子模式#7匹配。而「V」匹配子模式#9。第一次迭代完成,匹配「VMV」。
現在剩餘的目標字符串看起來像「ARGDLGVE」。 pos
標記位於3(目標字符串中的第4個字符),因此第二次迭代的匹配從那裏開始。 'A'匹配於子模式#3,'R'匹配#4,'G'匹配#5,'D'匹配#6,'L'匹配#7,'G'匹配#8,'' V'在#9匹配,'E'在#10匹配。第二次迭代完成後,匹配來自目標字符串的'ARGDLGVE'。
在第三次迭代中,pos
標記位於11,位於目標字符串中最後一個字符之後。所以空字符串會與您的正則表達式進行比較。因爲正則表達式中的每個量詞都是「0或1」,所以正則表達式匹配空字符串是可以接受的。所以第三次迭代完成後,匹配「」(空字符串)。
你有三個匹配:「VMV」,「ARGDLGVE」和「」。
你可能希望做的一件事是控制pos
標記。在while循環中放置正則表達式,並在循環終止之前,從字符串的起始位置再前進pos
。但是這隻能解決你在上述第三條規則中遇到的問題。你仍然會遇到這樣的問題,即量詞從事非常具體的事情,並且不會因爲你認爲它會很方便而違反他們自己的規則。
問題是,正則表達式引擎不是一個置換引擎。它的工作是確定一個給定的目標字符串是否與給定的模式相匹配,遵循一套定義明確的規則(儘管有時會引起混淆)。
我不確定你想要解決的大問題是什麼。如果您只是試圖擴大一系列範圍,那麼CPAN模塊String::Range::Expand可能會取得更好的成效。可能還有其他CPAN模塊可以爲你做範圍擴展,但這可能是一個很好的起點。
首先'使用strict'和'use warnings'。然後,你有很多不必要的字符類。並考慮使用'while'而不是'if'。 –
這是一個無限循環,如果我使用while .. – Rezwan
噢對不起,你將不得不使用另一個正則表達式。我會研究它。 –