[英]Perl Regex Multiple Matches
我正在尋找一個表現如下的正則表達式:
輸入:“你好世界”。
輸出:he,el,ll,lo,wo或rl,ld
我的想法是有道理的
while($string =~ m/(([a-zA-Z])([a-zA-Z]))/g) {
print "$1-$2 ";
}
但這確實有點不同。
這很棘手。 您必須捕獲它,保存它,然后強制回溯。
你可以這樣做:
use v5.10; # first release with backtracking control verbs
my $string = "hello, world!";
my @saved;
my $pat = qr{
( \pL {2} )
(?{ push @saved, $^N })
(*FAIL)
}x;
@saved = ();
$string =~ $pat;
my $count = @saved;
printf "Found %d matches: %s.\n", $count, join(", " => @saved);
產生這個:
Found 8 matches: he, el, ll, lo, wo, or, rl, ld.
如果您沒有v5.10,或者您頭疼,可以使用:
my $string = "hello, world!";
my @pairs = $string =~ m{
# we can only match at positions where the
# following sneak-ahead assertion is true:
(?= # zero-width look ahead
( # begin stealth capture
\pL {2} # save off two letters
) # end stealth capture
)
# succeed after matching nothing, force reset
}xg;
my $count = @pairs;
printf "Found %d matches: %s.\n", $count, join(", " => @pairs);
這產生與以前相同的輸出。
但是你可能仍然會頭疼。
不需要“強制回溯”!
push @pairs, "$1$2" while /([a-zA-Z])(?=([a-zA-Z]))/g;
雖然您可能希望匹配任何字母而不是您指定的有限集。
push @pairs, "$1$2" while /(\pL)(?=(\pL))/g;
還有另一種方法。 不使用任何正則表達式魔法,它確實使用嵌套map
但如果需要,這可以很容易地轉換為for
循環。
#!/usr/bin/env perl
use strict;
use warnings;
my $in = "hello world.";
my @words = $in =~ /(\b\pL+\b)/g;
my @out = map {
my @chars = split '';
map { $chars[$_] . $chars[$_+1] } ( 0 .. $#chars - 1 );
} @words;
print join ',', @out;
print "\n";
同樣,對我來說,這比一個奇怪的正則表達式YMMV更具可讀性。
您可以通過查找字母並使用pos
函數來使用捕獲的位置, \\G
在另一個正則表達式中引用它,並使用substr
從字符串中讀取幾個字符。
use v5.10;
use strict;
use warnings;
my $letter_re = qr/[a-zA-Z]/;
my $string = "hello world.";
while( $string =~ m{ ($letter_re) }gx ) {
# Skip it if the next character isn't a letter
# \G will match where the last m//g left off.
# It's pos() in a regex.
next unless $string =~ /\G $letter_re /x;
# pos() is still where the last m//g left off.
# Use substr to print the character before it (the one we matched)
# and the next one, which we know to be a letter.
say substr $string, pos($string)-1, 2;
}
您可以使用零寬度正斷言(?=pattern)
將“檢查下一個字母”邏輯放在原始正則表達式中。 零寬度意味着它沒有被捕獲並且不會提升m//g
正則表達式的位置。 這有點緊湊,但零寬度斷言變得棘手。
while( $string =~ m{ ($letter_re) (?=$letter_re) }gx ) {
# pos() is still where the last m//g left off.
# Use substr to print the character before it (the one we matched)
# and the next one, which we know to be a letter.
say substr $string, pos($string)-1, 2;
}
更新 :我最初嘗試捕獲匹配和m{ ($letter_re (?=$letter_re)) }gx
為m{ ($letter_re (?=$letter_re)) }gx
但這不起作用。 向前看是零寬度並且滑出比賽。 其他人的答案顯示,如果你在預測中放入第二個捕獲,那么它可以崩潰到......
say "$1$2" while $string =~ m{ ($letter_re) (?=($letter_re)) }gx;
我在這里留下TMTOWTDI的所有答案,特別是如果你不是一個正則表達式的主人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.