[英]Match from last occurrence using regex in perl
我有這樣的文字:
hello world /* select a from table_b
*/ some other text with new line cha
racter and there are some blocks of
/* any string */ select this part on
ly
////RESULT rest string
文本是多行的,我需要從最后一次出現的“* /”中提取,直到“//// RESULT”。 在這種情況下,結果應該是:
select this part on
ly
如何在perl中實現這一目標?
我\\\\\\*/(.|\\n)*////RESULT
但是從第一個“* /”開始
在這種情況下,一個有用的技巧是在regexp前加上貪婪模式.*
,它會在模式的其余部分匹配之前嘗試匹配盡可能多的字符。 所以:
my ($match) = ($string =~ m!^.*\*/(.*?)////RESULT!s);
讓我們將這種模式分解為其組成部分:
^.*
從字符串的開頭開始,並盡可能多地匹配字符。 ( s
修飾符允許.
甚至匹配換行符。)字符串開頭的錨點^
不是絕對必要的,但它確保正則表達式引擎在匹配失敗時不會浪費太多時間回溯。
\\*/
只匹配文字字符串*/
。
(.*?)
匹配並捕獲任意數量的字符; 的?
使它不合適,所以它更喜歡匹配盡可能少的字符,以防有一個以上的位置,其余的正則表達式可以匹配。
最后, ////RESULT
只是匹配自己。
由於該模式包含很多斜線,並且因為我想避免傾斜牙簽綜合症 ,所以我決定使用替代的regexp分隔符。 感嘆號( !
)是一種流行的選擇,因為它們不會與任何正常的正則表達式語法沖突。
編輯:下面與ikegami的討論,我想我應該注意,如果你想在更長的正則表達式中使用這個正則表達式作為子模式,並且如果你想保證匹配的字符串(.*?)
永遠不會包含////RESULT
,那么你應該將regexp的那些部分包裝在一個獨立的(?>)
子表達式中 ,如下所示:
my $regexp = qr!\*/(?>(.*?)////RESULT)!s;
...
my $match = ($string =~ /^.*$regexp$some_other_regexp/s);
(?>)
導致其中的模式失敗而不是接受次優匹配(即超出匹配////RESULT
的第一個子串的匹配),即使這意味着正則表達式的其余部分將無法匹配。
(?:(?!STRING).)*
匹配任意數量的不包含STRING
的字符。 它就像[^a]
,但是對於字符串而不是字符。
如果您知道不會遇到某些輸入(如Kenosis和Ilmari Karonen所做的那樣),您可以使用快捷方式,但這與您指定的內容相符:
my ($segment) = $string =~ m{
\*/
( (?: (?! \*/ ). )* )
////RESULT
(?: (?! \*/ ). )*
\z
}xs;
如果您不關心*/
////RESULT
之后是否出現*/
,則以下是最安全的:
my ($segment) = $string =~ m{
\*/
( (?: (?! \*/ ). )* )
////RESULT
}xs;
如果有兩個////RESULT
跟隨最后一個*/
,則沒有指定會發生什么。 以上匹配直到最后一個。 如果你想匹配到第一個,你可以使用
my ($segment) = $string =~ m{
\*/
( (?: (?! \*/ | ////RESULT ). )* )
////RESULT
}xs;
這是一個選項:
use strict;
use warnings;
my $string = <<'END';
hello world /* select a from table_b
*/ some other text with new line cha
racter and there are some blocks of
/* any string */ select this part on
ly
////RESULT
END
my ($segment) = $string =~ m!\*/([^/]+)////RESULT$!s;
print $segment;
輸出:
select this part on
ly
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.