2012-08-07 1 views
11

정규식 플래그를 비롯하여 Perl 정규식을 serialize해야하는 일부 코드 작업 중입니다. 플래그의 하위 집합 만 지원되므로 /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.에서 펄 함수를 호출

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'가 초 대신 꺼집니다. – 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를 확인하는 것보다 더 많은 작업이 필요합니다.