4

perl 正規表現で一致したサブパターンで算術演算を行う方法を理解したいです。\1これは単なるサンプル コードであり、どのように(すでに一致したサブパターン。この場合は - 7) を使用して一致させることができるかを理解したいと考えています。pattern+1 (8)

my $y = 77668;
if($y =~ /(\d)\1(\d)\2\1+1/)   #How to increment a previously
                               #matched sub-pattern and form a pattern?
{
    print $y;
}

編集

回答から、パターン演算は不可能であることがわかります。

これが私が達成したいことです。
このパターンに一致する正規表現を作成したい:

N-3N-2N-1NNN+1N+2N+3    (N = 3,4,5,6
4

2 に答える 2

6

もちろん、これは可能です。結局のところ、Perl正規表現について話しているのです。しかし、それはかなり醜いでしょう:

say "55336"=~m{(\d)\1(\d)\2(\d)(?(?{$1+1==$3})|(*F))}?"match":"fail";

またはきれいに印刷された:

say "55336" =~ m{  (\d)\1 (\d)\2 (\d)
                   (?  (?{$1+1==$3}) # true-branch: nothing
                                   |(*FAIL)
                   )
                }x
     ? "match" : "fail";

これは何をしますか?通常のキャプチャで数字を収集します。最後に、if-elseパターンを使用します。

(? (CONDITION) TRUE | FALSE )

を使用して正規表現にコードを埋め込むことができます(?{ code })。このコードの戻り値を条件として使用できます。((*FAIL)short (*F):)動詞は、一致を失敗させます。(*PRUNE)パターン全体が失敗するのではなく、ブランチのみが必要な場合に使用します。

埋め込みコードはデバッグにも最適です。ただし、古いperlsは、この正規表現コード内で正規表現を使用できません:-(

したがって、多くのものを照合し、パターン自体の内部で有効性をテストできます。ただし、次のようなパターンのでそれを行う方がよい場合があります。

 "string" =~ /regex/ and (conditions)

次に、メインパターンについて説明します(正しく解析したことN-3N-2N-1NNN+1N+2N+3を願っています)。

my $super_regex = qr{
        # N -3 N-2 N-1 N N N+1 N+2 N+3
        (\d)-3\1-2\1-1\1\1(\d)(\d)(\d)
        (?(?{$1==$2-1 and $1==$3-2 and $1==$4-3})|(*F))
    }x;

say "4-34-24-144567" =~ $super_regex ? "match" : "fail";

またはあなたは意味しました

my $super_regex = qr{
        #N-3 N-2 N-1  N  N   N+1 N+2 N+3
        (\d)(\d)(\d) (\d)\4 (\d)(\d)(\d)
        (?  (?{$1==$4-3 and $2==$4-2 and $3==$4-1 and
               $5==$4+1 and $6==$4+2 and $7==$4+3})|(*F))
    }x;

say "123445678" =~ $super_regex ? "match" : "fail";

怖いのは、これらも機能することです(perl5.12で)。

コンストラクトを使用して、一致時にパターンの一部を生成することもでき(??{ code })ます。このコードの戻り値は、パターンとして使用されます。

my $super_regex = qr{(\d)(??{$1+1})(??{$1+2})}x;
say "234"=~$super_regex ? "match":"fail"

等。ただし、この方法では読みやすさがさらに低下すると思います。

9つを超えるキャプチャが必要な場合は、名前付きキャプチャを使用できます。

(?<named>pattern) ... \k<named>

構成します。内容は%+ハッシュでも利用できます。詳細については、perlvarを参照してください。

Perl正規表現の秘密をさらに掘り下げるために、 perlreを数回読むことをお勧めします。

于 2012-11-10T18:46:36.033 に答える
6

正規表現コードブロックを介して可能です:

my $y = 77668;
if($y =~ /(\d)\1(\d)\2(??{$1+1})/ ) {
    print $y;
}

このスニペット(??{ CODE })では、一致する必要がある別の正規表現が返されるため、この正規表現は "8" ($1+1) のようになります。その結果、正規表現全体は、5 桁目が大きく、1 桁目が 1 の場合にのみ一致します。ただし、1 桁目の欠点は 9 です。このコード ブロックは「10」を返すため、間違った動作の可能性がありますが、何をすべきかについては何も言いませんでした。この場合行われます。

質問についてN-3N-2N-1NNN+1N+2N+3は、次の正規表現と一致させることができます。

my $n = 5;
if( $y =~ /(??{ ($n-3).($n-2).($n-1).$n.($n+1).($n+2).($n+3) })/ ){

または、より「スケーラブル」な方法:

my $n = 5;
if( $y =~ /(??{ $s=''; $s .= $n+$_ foreach(-3..3); $s; })/ ){

繰り返しますが、$n == 2 の場合はどうすればよいでしょうか?? $n-3 は -1 になります。単なる数字ではなく、符号があるため、この場合について考える必要があります。

もう一つの方法。私たちが持っているものと一致させてから、それを確認してください。

if( $y =~ /(\d)(\d)(\d)(\d)(\d)(\d)(\d)/ ) {
    if( $1 == ($4-3) && $2 == ($4-2) && $3 == ($4-1) && $6 == ($4+1) && $7 == ($4+2) && $7 == ($4+3) ) {
        #...

この方法は少し不器用に思えますが、誰にとっても明らかです (願っています)。

また、7 つの昇順の連続数字はそれほど頻繁に組み合わせられるわけではないため、正規表現を最適化できます。

sub check_number {
    my $i;
    for($i=1; $i<length($^N); $i++) {
        last if substr($^N, $i, 1)<=substr($^N, $i-1, 1);
    }
    return $i<length($^N) ? "(*FAIL)" : "(*ACCEPT)";
}

if( $y =~ /[0123][1234][2345][3456][4567][5678][6789](??{ check_number() })/ ) {

または...おそらく最も人間に優しい方法:

if( $y =~ /0123456|1234567|2345678|3456789/ ) {

最後のバリアントは bingo xD のようです物事が非常に単純な場合に正規表現を検索しないという良い例です)

于 2012-11-10T19:24:41.473 に答える