pcre 에서 여러개의 pattern 찾기...

서지훈의 이미지

예를 들어 "abcdef abcdef" 라는 문자열이 있는데...
"cd"라는 무나열 패턴을 찾기를 원하는데, pcre_exec()를 이용하니 return 값이 항상 1이군요.
2가 나와야 하고, 2번을 돌아야 할텐데...
예제를 봐도 패턴 만큼 나오는것 같은데 ㅡㅡㅋ
pcre_compile()과 pcre_exec()실행시 option값은 0입니다.

함...
혹시나 해서 사용한 부분 소스 올립니다.

    /*  Compile the regular expression in the first argument */
    re = pcre_compile(
            pc_pattern,     /* the pattern */
            0,           /* default options */
            //PCRE_EXTENDED,           /* default options */
            &error,      /* for error message */
            &erroffset,  /* for error offset */
            NULL);       /* use default character tables */

    /* execute */
    rc = pcre_exec(
            re,         /* the compiled pattern */
            NULL,       /* we didn't study the pattern */
            pc_str,     /* the subject string */
            (int)strlen(pc_str), /* the length of the subject */
            0,           /* start at offset 0 in the subject */
            0,           /* default options */
            o_vector,     /* vector for substring information */
            OVECCOUNT);  /* number of elements in the vector */

배고파서 밥먹으로 가야 겠네요 ㅡㅡㅋ
다들 저녁 맛나게들 드시길 ...

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

ai의 이미지

pcre_exec 의 반환값은 const pcre *code 매치된 개수가 아닙니다. 보통은 아래처럼 루프를 돌게 되는데, 자세한 내용은 pcre 예제를 보시면 됩니다.

re = pcre_compile(pattern, ...);
if (!re) { /* error */ }

/* 1st stage */
rc = pcre_exec(re, ...); /* startoffset = 0 */
if (rc<0) { switch(rc) { /* error */ } }
/* check ovector here */

/* 2nd stage */
while (1)
{
  rc = pcre_exec(re, ...); /* startoffset = previous *(ovector+1) */
  if (condition) { break; }
  if (rc<0) { switch(rc) { /* error */} }
  /* check ovector here */
}

예외처리나 옵션 등은 생략했습니다.

War doesnt determine whos right, just whos left.

서지훈의 이미지

그럼...

         #include <stdio.h>
         #include <string.h>
         #include <pcre.h>

         #define OVECCOUNT 30    /* should be a multiple of 3 */

         int main(int argc, char **argv)
         {
         pcre *re;
         const char *error;
         int erroffset;
         int ovector[OVECCOUNT];
         int rc, i;

         if (argc != 3)
           {
           printf("Two arguments required: a regex and a "
             "subject string\n");
           return 1;
           }

         /*  Compile the regular expression in the first argument
       */

         re = pcre_compile(
           argv[1],     /* the pattern */
           0,           /* default options */
           &error,      /* for error message */
           &erroffset,  /* for error offset */
           NULL);       /* use default character tables */

         /* Compilation failed: print the error message and  exit
       */

         if (re == NULL)
           {
           printf("PCRE compilation failed at offset %d: %s\n",
             erroffset, error);
           return 1;
           }
         /*  Compilation succeeded: match the subject in the sec?
       ond
            argument */

         rc = pcre_exec(
           re,          /* the compiled pattern */
           NULL,        /* we didn't study the pattern */
           argv[2],     /* the subject string */
           (int)strlen(argv[2]), /* the length of the subject */
           0,           /* start at offset 0 in the subject */
           0,           /* default options */
           ovector,     /* vector for substring information */
           OVECCOUNT);  /* number of elements in the vector */

         /* Matching failed: handle error cases */

         if (rc < 0)
           {
           switch(rc)
             {
             case   PCRE_ERROR_NOMATCH:   printf("No   match\n");
       break;
             /*
             Handle other special cases if you like
             */
             default: printf("Matching error %d\n", rc); break;
             }
           return 1;
           }

         /* Match succeded */

         printf("Match succeeded\n");

         /* The output vector wasn't big enough */

         if (rc == 0)
           {
           rc = OVECCOUNT/3;
           printf("ovector only has room for %d captured "
             substrings\n", rc - 1);
           }

         /* Show substrings stored in the output vector */

===>  for (i = 0; i < rc; i++)
           {
           char *substring_start = argv[2] + ovector[2*i];
           int substring_length = ovector[2*i+1] - ovector[2*i];
           printf("%2d: %.*s\n", i, substring_length,
             substring_start);
           }

         return 0;
         }

이게 man 에서 나오는 예제인데 저기 for()문은 어떤 의미인지?
아무 의미가 없는 것인가요?

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

익명 사용자의 이미지

         if (rc < 0) 
           { 
           switch(rc) 
             { 
             ....
             } 
           return 1; 
           } 

         /* Match succeded */ 

         printf("Match succeeded\n"); 

!(rc<0) 에서 이미 매치를 한 상태입니다. 제 기억이 맞다면 rc 에는 매치된 reference 의 개수가 반환될겁니다. 그러니 패턴에 괄호가 들어간 형태라면 모든 매치된 문자열을 알아보기 위해 rc 기준으로 루프를 돌아야죠.
ai의 이미지

Anonymous wrote:
         if (rc < 0) 
           { 
           switch(rc) 
             { 
             ....
             } 
           return 1; 
           } 

         /* Match succeded */ 

         printf("Match succeeded\n"); 

!(rc<0) 에서 이미 매치를 한 상태입니다. 제 기억이 맞다면 rc 에는 매치된 reference 의 개수가 반환될겁니다. 그러니 패턴에 괄호가 들어간 형태라면 모든 매치된 문자열을 알아보기 위해 rc 기준으로 루프를 돌아야죠.

제가 쓴 글입니다. 로긴을 안했더니...;

War doesnt determine whos right, just whos left.

서지훈의 이미지

그러니깐... 앞의 예제에서 rc가 2가 되어야 하는데...
1으로 리턴 되니 제가 답답한 겁니다. ㅡㅡㅋ

혹시... 저의 설명이 잘 못 되었나요?

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

익명 사용자의 이미지

rc의 값은 발견된 오프셋의 개수입니다.

위 소스에서
ovector는 실제 오프셋이구요..그 ovector이 오프셋을 통해 문자열의 시작오프셋과 그 길이를 구해 올수 있습니다. overctor는 짝수 쌍으로 되어 있으며 홀수 인덱스에는 출현된 문자열이 끝나는 오프셋,홀수이전 인덱스에는 출현한 문자열의 오프셋이 들어있습니다.

php-4.x.x버전의 소스를 받으셔서

ext/pcre/ 아래에 있는 php_pcre.c 파일의 php_pcre_match함수를 잘 분석해 보시기 바랍니다.

익명 사용자의 이미지

여러개의 출현위치를 찾는다면 위의 예제소스에서 몇가지가 더 추가 되어야 합니다.:-)..그건 php의 php_pcre_match함수를 좀 분석해 보시면 해답이 나올겁니다.

ai의 이미지

서지훈 wrote:
그러니깐... 앞의 예제에서 rc가 2가 되어야 하는데...
1으로 리턴 되니 제가 답답한 겁니다. ㅡㅡㅋ

혹시... 저의 설명이 잘 못 되었나요?

<어떠한 역경에도 굴하지 않는 '하양 지훈'>


손님들께서 이미 설명을 하셨지만.. 지훈님께서 제시하신 원 글에는 찾을 패턴이 "cd" 입니다. 이런 경우 의미를 가지는 ovector 는 아래와 같고, rc==1 이라는 의미는 perl 에서 $& 만 존재한다는 의미가 됩니다.
*(ovector+0)  // $& 의 시작 offset
*(ovector+1)  // $& 의 종료 offset

만약 패턴을 "(cd).(f)" 로 pcre_compile 하셨다면 의미를 가지는 ovector 는 아래와 같고, rc==3 이라는 의미는 perl 에서 $&, $1, $2 세 변수를 이용할 수 있다는 의미가 됩니다.
*(ovector+0)  // $& 의 시작 offset
*(ovector+1)  // $& 의 종료 offset
*(ovector+2)  // $1 의 시작 offset
*(ovector+3)  // $1 의 종료 offset
*(ovector+4)  // $2 의 시작 offset
*(ovector+5)  // $2 의 종료 offset

제가 제시한 pseudo code 에서는 while(1) 루프가 있는데, 이것은 pcre_exec 가 한 번의 패턴매칭만 수행하기 때문에 추가한 것입니다. (global match)

원래가 "abcdef abcdef" 에서 "cd" 가 나타나는 위치를 모두 얻고 싶으셨던게 아닌가요? 지훈님께서 인용하신 pcre 예제에는 stage 1 밖에 없기 때문에 처음 찾는 "cd" 의 위치만 얻을 수 있습니다. 다음 "cd" 의 위치를 얻기 위해서는 pcre_exec 의 startoffset 을 첫 출현한 "cd" 다음으로 놓고 다시 pcre_exec 해야 합니다. 몇 개라도 "cd" 를 모두 찾으려면 while(1) 안에서 pcre_exec 를 반복적으로 수행하고, 특정한 조건 (options, rc) 에 따라 break 하는 코드가 추가되어야 합니다.

War doesnt determine whos right, just whos left.

서지훈의 이미지

다들 하시는 말씀은 이해를 하겠는데 ㅡㅡㅋ
제가 궁금한건 딴게 아니라...

위의 man page에서 사용한 예제가 이상한게 아닌가 하는거죠?
지금까지 답변을 달아 주신분들의 말씀대로라면...
for ()문은 절대 돌 수가 없는 건데 왜 ... ?
사용을 했을까 하는 것입니다.

그냥... 저자의 실수...
뭐... 이정도의 대답을 원했는데 ㅡㅡㅋ
얘기가 하면 할수록 갭이 커지고 길어 지는 군요 ㅡㅡㅋ

그리고 ( rc == 3 ) 이라는 값이 나올려면 대략 어떻게 구성해야 가능 한건가요?
( rc == 3 )이라는 값이 가능한 것인가요?
pcre_exec()를 돌리는 1 or 0 or negative integer 값들만 나오는게 아닌지?
지금 말씀을 하신 것으로서는 그렇게 밖에 생각을 할 수 없을 듯 한데요 ㅡㅡㅋ

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

익명 사용자의 이미지

손님및 ai님이 하신 말씀을 제대로 이해하지 못하신거 같군요.

저기에서 for문의 역활은 매치된 스트링을 찾는 역활을 하는것입니다..rc값은 매치된 개수이구요. 당연히 매치된 개수만큼 for문을 돌면서 오프셋을 빼고 더하고 해서 스트링을 끄집어 내야 겠지요.

님께서 man을 통해 얻은 소스는 ai님께서 말씀하신대로 한번의 매치밖에 못가져 옵니다.그래서 반복적으로 start offset를 변경해가면서 루프를 돌며 pcre_exec 해주면 모든 매치스트링을 얻어낼수 있다는 말이죠.

ai의 이미지

서지훈 wrote:
다들 하시는 말씀은 이해를 하겠는데 ㅡㅡㅋ
제가 궁금한건 딴게 아니라...

위의 man page에서 사용한 예제가 이상한게 아닌가 하는거죠?
지금까지 답변을 달아 주신분들의 말씀대로라면...
for ()문은 절대 돌 수가 없는 건데 왜 ... ?
사용을 했을까 하는 것입니다.

그냥... 저자의 실수...
뭐... 이정도의 대답을 원했는데 ㅡㅡㅋ
얘기가 하면 할수록 갭이 커지고 길어 지는 군요 ㅡㅡㅋ

그리고 ( rc == 3 ) 이라는 값이 나올려면 대략 어떻게 구성해야 가능 한건가요?
( rc == 3 )이라는 값이 가능한 것인가요?
pcre_exec()를 돌리는 1 or 0 or negative integer 값들만 나오는게 아닌지?
지금 말씀을 하신 것으로서는 그렇게 밖에 생각을 할 수 없을 듯 한데요 ㅡㅡㅋ

<어떠한 역경에도 굴하지 않는 '하양 지훈'>


왜 저자의 실수라고 생각하시나요? rc==3 을 얻기 위해서 "(cd).(f)" 라는 패턴을 말씀드렸지 않습니까. 제가 잘못 알고 있는게 아닌지 걱정이 되는군요.

War doesnt determine whos right, just whos left.

익명 사용자의 이미지

구글에서 pcre_exec로 검색하면 이 글이 두 번째입니다.
ai님이 잘 답변하셨지만 읽다보면 혼란스러운 부분이 있어 정리가 좀 더 필요한 듯해, 오래된 글이지만 다른 사람을 위해 내용을 추가합니다.

최초 질문자는 subject인 "abcdef abcdef" 에서 "cd"를 찾기위해 pcre_exec()를 실행했더니 항상 1이 리턴되는데 이게 맞는지를 물었습니다.
왜냐면 subject에는 "cd"가 포함된 부분이 2군데니까 2가 나와야하지 않느냐고 생각한 듯 합니다.

하지만 pcre_exec()의 리턴값은 subpattern 개수이고 패턴 "cd"는 subpattern이 없기 때문에 항상 1이 리턴됩니다.

ai님의 답변에 ( rc == 3 )을 얻기 위해서는 패턴에 "cd" 대신 "(cd).(f)"를 지정하면 된다는 내용이 있습니다.
이렇게 하면 매치된 문자열 1은 "cdef", 2는 "cd", 3은 "f"가 되고 rc역시 3이 나오죠.

어떻게 하든 이 매칭은 앞쪽의 "abcdef"에 대해서만 진행되므로 뒤쪽의 "abcdef"에 대해서도 매칭을 하려면 pcre_exec()를 한번 더 실행해야 합니다.
그리고 이 때 pcre_exec()의 인수 중 start offset을 0 대신 뒤쪽 단어의 시작 offset으로 지정해야 합니다(아마 *(ovector+1) + 1이 되겠죠).

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.