Pertanyaan Apakah Perl `(? PARNO)` membuang namanya sendiri ketika selesai?


Apakah regex rekursif memahami tangkapan bernama? Ada catatan di dokumen untuk (?{{ code }}) bahwa itu adalah subpattern independen dengan kumpulan tangkapan sendiri yang dibuang saat subpattern selesai, dan ada catatan di (?PARNO) yang "mirip dengannya (?{{ code }}). Aku s (?PARNO) membuang namanya sendiri ketika selesai?

Saya sedang menulis tentang ekspresi reguler rekursif Perl Menguasai Perl. perlre sudah memiliki contoh dengan orang tua yang seimbang (saya tunjukkan dalam Mencocokkan kurung seimbang dalam Perl regex), jadi saya pikir saya akan mencoba tanda kutip yang seimbang:

#!/usr/bin/perl
# quotes-nested.pl

use v5.10;

$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE

say "Matched!" if m/
    (
        ['"]
            ( 
                (?: 
                    [^'"]+
                    | 
                    ( (?1) ) 
                )* 
            )
        ['"]
    )
    /xg;

print "
1 => $1
2 => $2
3 => $3
4 => $4
5 => $5
";

Ini berfungsi dan dua kutipan muncul $1 dan $3:

Matched!
1 => 'Amelia said "I am a camel"'
2 => Amelia said "I am a camel"
3 => "I am a camel"
4 => 
5 => 

Tidak apa-apa. Aku mengerti itu. Namun, saya tidak ingin tahu jumlahnya. Jadi, saya membuat grup tangkapan pertama yang bernama ambil dan lihat %- berharap melihat dua substring yang saya lihat sebelumnya $1 dan $2:

use v5.10;

$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE

say "Matched [$+{said}]!" if m/
    (?<said>
        ['"]
            ( 
                (?: 
                    [^'"]+
                    | 
                    (?1) 
                )* 
            )
        ['"]
    )
    /xg;

use Data::Dumper;
print Dumper( \%- );

Saya hanya melihat yang pertama:

Matched ['Amelia said "I am a camel"']!
$VAR1 = {
          'said' => [
                      '\'Amelia said "I am a camel"\''
                    ]
        };

Saya mengharapkan itu (?1) akan mengulang semuanya di grup tangkapan pertama, termasuk penangkapan yang bernama ke said. Saya dapat memperbaikinya sedikit dengan menamai tangkapan baru:

use v5.10;

$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE

say "Matched [$+{said}]!" if m/
    (?<said>
        ['"]
            ( 
                (?: 
                    [^'"]+
                    | 
                    (?<said> (?1) ) 
                )* 
            )
        ['"]
    )
    /xg;

use Data::Dumper;
print Dumper( \%- );

Sekarang saya mendapatkan apa yang saya harapkan:

Matched ['Amelia said "I am a camel"']!
$VAR1 = {
          'said' => [
                      '\'Amelia said "I am a camel"\'',
                      '"I am a camel"'
                    ]
        };

Saya pikir saya bisa memperbaikinya dengan memindahkan yang bernama ambil satu tingkat:

use v5.10;

$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE

say "Matched [$+{said}]!" if m/
    (
        (?<said>
        ['"]
            ( 
                (?: 
                    [^'"]+
                    | 
                    (?1)
                )* 
            )
        ['"]
        )
    )
    /xg;

use Data::Dumper;
print Dumper( \%- );

Namun, ini tidak menangkap substring yang lebih kecil di said antara:

Matched ['Amelia said "I am a camel"']!
$VAR1 = {
          'said' => [
                      '\'Amelia said "I am a camel"\''
                    ]
        };

Saya rasa saya mengerti ini, tetapi saya juga tahu bahwa ada orang di sini yang benar-benar menyentuh kode C yang membuatnya terjadi. :)

Dan, ketika saya menulis ini, saya pikir saya harus membebani dasi STORE untuk %- untuk mencari tahu, tetapi kemudian saya harus mencari tahu cara melakukannya.


32
2017-10-01 18:31


asal


Jawaban:


Setelah bermain-main dengan ini, saya puas bahwa apa yang saya katakan dalam pertanyaan itu benar. Setiap panggilan ke (?PARNO) mendapat set lengkap dan terpisah dari variabel pertandingan yang dibuang di akhir prosesnya.

Anda bisa mendapatkan semua hal yang cocok dalam setiap pola sub dengan menggunakan array eksternal ke operator pencocokan pola dan mendorongnya ke ujung sub pola berulang, seperti dalam contoh ini:

#!/usr/bin/perl
# nested_carat_n.pl

use v5.10;

$_ =<<'HERE';
Outside "Top Level 'Middle Level "Bottom Level" Middle' Outside"
HERE

my @matches;

say "Matched!" if m/
    (?(DEFINE)
        (?<QUOTE_MARK> ['"])
        (?<NOT_QUOTE_MARK> [^'"])
    )
    (
    (?<quote>(?&QUOTE_MARK))
        (?:
            (?&NOT_QUOTE_MARK)++
            |
            (?R)
        )*
    \g{quote}
    )
    (?{ push @matches, $^N })
    /x;

say join "\n", @matches;

Saya membahasnya secara mendalam Bab 2 Menguasai Perl, yang dapat Anda baca secara gratis (setidaknya untuk sementara).


4
2017-11-15 22:41