How to introspect regexes in the Perl API

前端 未结 2 634

I\'m working on some code that needs to serialize Perl regexes, including any regex flags. Only a subset of flags are supported, so I need to detect when unsupported flags like

2条回答
  •  难免孤独
    2021-02-20 05:39

    In Perl, you'd use re::regexp_pattern.

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

    As you can see from the source of regexp_pattern, there's no function in the API to obtain that information, so I recommend that you call that function too from XS too.

    perlcall covers calling Perl functions from C. I came up with the following untested code:

    /* 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;
    }
    

    Usage:

    SV * re = ...;
    
    char * pat;
    char * flags;
    regexp_pattern(&pat, &flags, re);
    

提交回复
热议问题