2012-08-07 9 views
11

正規表現のフラグを含め、Perl正規表現をシリアライズする必要があるコードに取り組んでいます。フラグのサブセットのみがサポートされているので、/uのようなサポートされていないフラグが正規表現オブジェクトに含まれていることを検出する必要があります。Perl APIで正規表現をイントロスペクションする方法

コードの現在のバージョンがこれを行う:

static void serialize_regex_flags(buffer *buf, SV *sv) { 
    char flags[] = {0,0,0,0,0,0}; 
    unsigned int i = 0, f = 0; 
    STRLEN string_length; 
    char *string = SvPV(sv, string_length); 

手動フラグを見つけるために、stringチャー・バイ・チャーを処理します。

ここでの問題は、regexフラグの文字列化がPerl 5.14で変更されたことです。 (?i-xsm:foo)(?^i:foo)となり、解析に苦労します。

perlのバージョンを確認したり、両方のケースを処理するパーサを作成したりできますが、イントロスペクションの優れた方法があることが必要です。

答えて

6

Perlでは、re::regexp_patternを使用します。あなたがregexp_patternのソースから見ることができるように

my $re = qr/foo/i; 
my ($pat, $mods) = re::regexp_pattern($re); 
say $pat; # foo 
say $mods; # i 

は、その情報を取得するAPIには機能がありませんので、私はあなたがあまりにもXSからあまりにもその関数を呼び出すことをお勧めします。私は、次の未テストコードを思い付いたCからPerlの関数を呼び出す

perlcallカバー:

/* Calls re::regexp_pattern to extract the pattern 
* and flags from a compiled regex. 
* 
* When re isn't a compiled regex, returns false, 
* and *pat_ptr and *flags_ptr are set to NULL. 
* 
* The caller must free() *pat_ptr and *flags_ptr. 
*/ 

static int regexp_pattern(char ** pat_ptr, char ** flags_ptr, SV * re) { 
    dSP; 
    int count; 
    ENTER; 
    SAVETMPS; 
    PUSHMARK(SP); 
    XPUSHs(re); 
    PUTBACK; 
    count = call_pv("re::regexp_pattern", G_ARRAY); 
    SPAGAIN; 

    if (count == 2) { 
     /* Pop last one first. */ 
     SV * flags_sv = POPs; 
     SV * pat_sv = POPs; 

     /* XXX Assumes no NUL in pattern */ 
     char * pat = SvPVutf8_nolen(pat_sv); 
     char * flags = SvPVutf8_nolen(flags_sv); 

     *pat_ptr = strdup(pat); 
     *flags_ptr = strdup(flags); 
    } else { 
     *pat_ptr = NULL; 
     *flags_ptr = NULL; 
    } 

    PUTBACK; 
    FREETMPS; 
    LEAVE; 

    return *pat_ptr != NULL; 
} 

使用法:

SV * re = ...; 

char * pat; 
char * flags; 
regexp_pattern(&pat, &flags, re); 
+0

私はこれが道だと思います行く、ありがとう – friedo

+0

@フリード、(未テスト)XSコードを追加しました。 – ikegami

+0

ありがとう、ikegami。私はCコードを出発点として必要なものを手に入れることができました。注目すべきは、戻り値を逆順にポップする必要があることです(つまり、 'flags_sv'が2番目ではなく最初に取り除かれます)。 – friedo

3
use Data::Dump::Streamer ':util'; 
my ($pattern, $flags) = regex(qr/foo/i); 
print "pattern: $pattern, flags: $flags\n"; 
# pattern: foo, flags: i 

最近の機能を制限しようとしている場合は、/ uを確認するだけではなりません。