POSIX BRE( Basic Regular Expression )

  1. ^
  2. $
  3. .
  4. *
  5. \
  6. (
  7. {
  8. [



6. ( ) ( Parenthesis, 소괄호 )

구문 ( Syntax )

<left_paren> ::= (

<right_paren> ::= )
  • 사용 예
    <group_expr>
    
    <group_expr><pattern_expr><back_slash><integer>
    
    <group_expr> ::= 
      <left_paren><pattern_expr><right_paren>
    
    <back_slash> ::= \
    
    

설명 ( Description )

  • 괄호는 <group_expr>의 <pattern_expr>을 그룹화( Grouping )한다.
    그룹화란, 괄호로 묶인 <pattern_expr>을 하나의 문자로 취급하는 것으로, 
    이를 통해 <pattern_expr>에서 메타문자들이 적용할 범위 및 순서를 지정할 수 있다.
    • ex) (abc)* =>  , abc, abcabc, abcabcabc, ...
    • ex) (t|m)ake => take or make
    • ex) (ab|(cd)*) => ab or  , cd, cdcd, ...
  • 그룹화해서 만들어지는 이 그룹들은 좌에서 우로 1번부터 차례대로 번호가 새겨진다. 
    그룹 시작의 기준은 <left_paren>이며, 그룹 끝의 기준은 <right_paren>이다.
    • ex)
      ex1)
      pattern : '(2019)-(03)-(27)'
      
      1번 그룹 : 2019
      2번 그룹 : 03
      3번 그룹 : 27
      
      
      ex2)
      pattern : '(1(23(45)6))'
      
      1번 그룹 : 123456
      2번 그룹 : 23456
      3번 그룹 : 45
      
      
      ex3)
      pattern : '(ab(cd)e(f))g(hijk)'
      
      1번 그룹 : abcdef
      2번 그룹 : cd
      3번 그룹 : f
      4번 그룹 : hijk
      
  • 또한 매칭 과정에서, 그룹화된 <pattern_expr>이 source string과 매칭하면 각각의 그룹에 매칭된 result 값을 저장한다.
    이 result 값을 'Subexpression'이라 한다.
    • ex)
      ex1)
      source string : 'abcde'
      pattern : '(a(bcd))(e)'
      
      1번 그룹에 string 'abcd'를 저장
      2번 그룹에 string 'bcd'를 저장
      3번 그룹에 string 'e'를 저장
      
      
      ex2)
      source string : 'abcde'
      pattern : '(..(..).)'
      
      1번 그룹에 string 'abcde'를 저장
      2번 그룹에 string 'cd'를 저장
      
  • 이렇게 저장된 Subexpression값을 괄호 밖에서 <back_slash><integer> 형태로 사용할 수 있으며 이를 'Back-reference ( 역 참조 )'라 한다.
    <integer>는 1 이상 9 이하의 정수이다.
    • ex)
      ex1)
      source string : 'abca'
      pattern : '(a)bc\1'
      
      1번 그룹에 string 'a'를 저장
      
      subexpression 1을 back-reference
      
      matched result : 'abca'
      
      
      ex2) 
      '마법 날짜'를 찾는 정규 표현식
      Finding 'Magic Date' which format 'yyyy-mm-dd'
      세기를 제외한 연도부분, 월 부분, 일 부분의 숫자가 모두 같은 날짜를 마법 날짜라 한다.
      
      source strings : '2010-10-10', '2009-11-26', '2004-04-04'
      pattern : '..(..)-\1-\1'
      
      matched result(s) : '2010-10-10', '2004-04-04'
      
      
      ex3)
      source string : 'abcdcdab'
      pattern : '(ab)(cd)\2\1'
      
      1번 그룹에 string 'ab'를 저장
      2번 그룹에 string 'cd'를 저장
      
      subexpression 2를 back-reference
      subexpression 1을 back-reference
      
      matched result : 'abcdcdab'
      
    • 그룹화는 10개 이상 가능하지만, 10번째 그룹부터는 역 참조할 수 없다.
      • ex) (1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)(12)
  • 역 참조한 Subexpression에 수량자 추가도 가능하다.
    • ex) (a)\1* => a, aa, aaa, ...
  • 역 참조한 Subexpression또한 그룹화 및 역 참조가 가능하다.
    • ex) (c)(b)(\2) => cbb
    • ex) (z)(\1)\2 => zzz

  • 그룹화를 하지 않고 역 참조를 하거나, 그룹화 하기 전에 역 참조를 먼저 할 경우 error 처리한다.
    • ex) a\1
    • ex) \1(a)
  • Subexpression 관련 문서
    • POSIX : POSIX 표준에서는 general한 'subexpression', 즉 말 그대로 하위 표현식 개념의 설명만 기재되어 있다.

    • Oracle Regular Expressions Pocket Reference에서 발췌
      • You can apply a quantifier to any arbitrary part of an expression simply by enclosing that part of the expression in parentheses.
        expression의 해당 부분을 괄호로 묶는 간단한 행동으로 expression의 임의의 부분에 수량자를 적용할 수 있다.
        The result is called a subexpression, and you can follow a subexpression with a quantifier to specify repetition.
        그 결과를 'subexpression'으로 부르며, 이 subexpression 다음에 수량자를 기재하여 반복시킬수 있다.


예제 ( Examples )

SQL> SELECT REGEXP_SUBSTR( 'abc', '(a)(bc)' ) AS RESULT FROM DUAL;

RESULT
------------------------------
abc

SQL> SELECT REGEXP_SUBSTR( 'abab', '(ab)*' ) AS RESULT FROM DUAL;

RESULT
--------------------
abab

SQL> SELECT REGEXP_SUBSTR( 'aabaabaac', '(a)*b\1' ) AS RESULT FROM DUAL;

RESULT
------------------------------
aaba

SQL> SELECT REGEXP_SUBSTR( 'aabaabaac', '(a*)b\1' ) AS RESULT FROM DUAL;

RESULT
------------------------------
aabaa

SQL> SELECT REGEXP_SUBSTR( 'aa', '(a)\1' ) AS RESULT FROM DUAL;

RESULT
--------------------
aa

SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)' ) AS RESULT FROM DUAL;

RESULT
--------------------
a

SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)\1' ) AS RESULT FROM DUAL;

RESULT
--------------------
bb

SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)\1\1' ) AS RESULT FROM DUAL;

RESULT
--------------------
ccc

SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(.)\2' ) AS RESULT FROM DUAL;

RESULT
--------------------
abb

  • 10개가 넘는 그룹화 및 역 참조
    < Oracle >
    SQL> SELECT REGEXP_SUBSTR( '12345678901112', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)(11)(12)' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    12345678901112
    
    SQL> SELECT REGEXP_SUBSTR( '12345678901', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)\1' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    12345678901
    
    SQL> SELECT REGEXP_SUBSTR( '12345678900', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)\10' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    NULL
    
    SQL> SELECT REGEXP_SUBSTR( '123456789010', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)\10' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    123456789010
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdefghijkli', '(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\9' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    abcdefghijkli
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdefghijklj', '(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\10' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    NULL
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdefghijkla0', '(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\10' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    abcdefghijkla0
    
    
    < MySQL >
    mysql> SELECT REGEXP_SUBSTR( '12345678901112', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)(11)(12)' ) AS RESULT;
    +----------------+
    | RESULT         |
    +----------------+
    | 12345678901112 |
    +----------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT REGEXP_SUBSTR( '12345678900', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)\\10' ) AS RESULT; 
    +-------------+
    | RESULT      |
    +-------------+
    | 12345678900 |
    +-------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT REGEXP_SUBSTR( '1234567890111212', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)(11)(12)\\12' ) AS RESULT;
    +------------------+
    | RESULT           |
    +------------------+
    | 1234567890111212 |
    +------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT REGEXP_SUBSTR( 'abcdefghijkll', '(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12' ) AS RESULT;
    +---------------+
    | RESULT        |
    +---------------+
    | abcdefghijkll |
    +---------------+
    1 row in set (0.00 sec)
    
    
     Oracle MySQL   10 이상의 그룹화가 가능하다.
    - Oracle \10 \1 스트링 0으로 처리한다.
    - MySQL 10 이상의 그룹도 가능하다.
    
    
    < MariaDB >
    MariaDB [test]> SELECT REGEXP_SUBSTR( '1234567890', '(1)(2)(3)(4)(5)(6)(7)(8)(9)' ) AS RESULT;
    +-----------+
    | RESULT    |
    +-----------+
    | 123456789 |
    +-----------+
    1 row in set (0.001 sec)
    
    MariaDB [test]> SELECT REGEXP_SUBSTR( '1234567899', '(1)(2)(3)(4)(5)(6)(7)(8)(9)\\9' ) AS RESULT;
    +------------+
    | RESULT     |
    +------------+
    | 1234567899 |
    +------------+
    1 row in set (0.001 sec)
    
    MariaDB [test]> SELECT REGEXP_SUBSTR( '1234567890', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)' ) AS RESULT;
    +--------+
    | RESULT |
    +--------+
    |        |
    +--------+
    1 row in set (0.000 sec)
    
    MariaDB [test]> SELECT REGEXP_SUBSTR( '12345678901', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)\\1' ) AS RESULT;
    +--------+
    | RESULT |
    +--------+
    |        |
    +--------+
    1 row in set (0.001 sec)
    
     MariaDB 그룹이 9개를 넘을 경우 아무것도 매칭하지 않는다.
    
  • Oracle REGEXP_SUBSTR 함수에 인자로 Subexpresison을 줄 경우
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)', 1, 1, 'i', '1' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    a
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(.)', 1, 1, 'i', '2' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    b
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(.)(.)', 1, 1, 'i', '3' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    b
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(.)\2(.)', 1, 1, 'i', '3' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    c
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(.)(.)(.)', 1, 1, 'i', '4' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    c
    
    SQL> SELECT REGEXP_SUBSTR( '1234567890', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)', 1, 1, 'i', '9' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    9
    
    SQL> SELECT REGEXP_SUBSTR( '1234567890', '(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)', 1, 1, 'i', '10' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    NULL
    
    
  • 역 참조한 Subexpression에 수량자(quantifier)를 추가할 수도 있다.
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)\1*', 1, 1 ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    a
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)\1*', 1, 2 ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    bb
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)\1*', 1, 3 ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    ccc
    
    
  • 역 참조한 Subexpression을 다시 그룹화 및 역 참조할 수 있다.
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(\1)' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    bb
    
    SQL> SELECT REGEXP_SUBSTR( 'abbccc', '(.)(\1)\2' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    ccc
    
    
  • zero-length match group
    SQL> SELECT REGEXP_SUBSTR( 'abc', '(d*)\1' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    NULL
    
    SQL> SELECT REGEXP_COUNT( 'abc', '(d*)\1' ) AS RESULT FROM DUAL;
    
        RESULT
    ----------
             4
    
    SQL> SELECT REGEXP_SUBSTR( 'abc', '(d*)(\1)\2' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    NULL
    
    SQL> SELECT REGEXP_COUNT( 'abc', '(d*)(\1)\2' ) AS RESULT FROM DUAL;
    
        RESULT
    ----------
             4
    
    
     그룹이 zero-length match 패턴이어도 back-reference 한다.
    
  • 그룹화 순서
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b(c(d(e)))))', 1, 1, 'm', 1 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    abcde
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b(c(d(e)))))', 1, 1, 'm', 2 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    bcde
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b(c(d(e)))))', 1, 1, 'm', 3 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    cde
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b(c(d(e)))))', 1, 1, 'm', 4 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    de
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b(c(d(e)))))', 1, 1, 'm', 5 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    e
    
    
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(((((a)b)c)d)e)', 1, 1, 'm', 1 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    abcde
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(((((a)b)c)d)e)', 1, 1, 'm', 2 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    abcd
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(((((a)b)c)d)e)', 1, 1, 'm', 3 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    abc
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(((((a)b)c)d)e)', 1, 1, 'm', 4 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    ab
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(((((a)b)c)d)e)', 1, 1, 'm', 5 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    a
    
    
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b))((cd)e)', 1, 1, 'm', 1 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    ab
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b))((cd)e)', 1, 1, 'm', 2 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    b
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b))((cd)e)', 1, 1, 'm', 3 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    cde
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdeabcde', '(a(b))((cd)e)', 1, 1, 'm', 4 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    cd
    
    SQL> SELECT REGEXP_SUBSTR( '11234567890', '(123)(4(56)(78))', 1, 1, 'm', 1 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    123
    
    SQL> SELECT REGEXP_SUBSTR( '11234567890', '(123)(4(56)(78))', 1, 1, 'm', 2 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    45678
    
    SQL> SELECT REGEXP_SUBSTR( '11234567890', '(123)(4(56)(78))', 1, 1, 'm', 3 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    56
    
    SQL> SELECT REGEXP_SUBSTR( '11234567890', '(123)(4(56)(78))', 1, 1, 'm', 4 ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    78
    
    
     그룹화는 괄호 시작'(' 부터 순서를 매긴다.
    
    
  • 그룹화를 하지 않고 역 참조
    SQL> SELECT REGEXP_SUBSTR( 'abcdabcd', 'ab\1' ) AS RESULT FROM DUAL;
    SELECT REGEXP_SUBSTR( 'abcdabcd', 'ab\1' ) AS RESULT FROM DUAL
                                      *
    ERROR at line 1:
    ORA-12727: invalid back reference in regular expression
    
    
  • 그룹화 하기 전에 역 참조
    SQL> SELECT REGEXP_SUBSTR( 'abcdabcd', '\1..(ab)..' ) AS RESULT FROM DUAL;
    SELECT REGEXP_SUBSTR( 'abcdabcd', '\1..(ab)..' ) AS RESULT FROM DUAL
                                      *
    ERROR at line 1:
    ORA-12727: invalid back reference in regular expression
    
    SQL> SELECT REGEXP_SUBSTR( 'abcdabcd', '(ab)\2..(cd)' ) AS RESULT FROM DUAL;
    SELECT REGEXP_SUBSTR( 'abcdabcd', '(ab)\2..(cd)' ) AS RESULT FROM DUAL
                                      *
    ERROR at line 1:
    ORA-12727: invalid back reference in regular expression
    
    


블로그 이미지

차트

소소한 일상 C코드 DB 항상 행복하게^-^★

,

POSIX BRE( Basic Regular Expression )

  1. ^
  2. $
  3. .
  4. *
  5. \
  6. (
  7. {
  8. [



5. \ ( Back Slash )

구문 ( Syntax )

<back_slash> ::= \
  • 사용 예
    <back_slash><meta_char>
    
    <meta_char> ::=
      ^
    | $
    | .
    | *
    | +
    | ?
    | |
    | \
    | (
    | )
    | {
    | [
    
    

설명 ( Description )

  • <back_slash> 뒤의 <meta_char>가 문자 그대로임을 의미한다. ( 이스케이프 처리 )
    • ex) \^
  • <back_slash>만 있는 경우
    • ex) \
    • 결과
      • Oracle : zero-length match
      • PostgreSQL, MySQL, MariaDB : error 처리
  • <back_slash> 뒤에 <meta_char>가 아닌 일반 문자가 있는 경우, 아무런 효과 없이 그 문자만을 매칭한다.
    • ex) \j
  • <back_slash> 뒤에 숫자가 올 수 없다.
    • ex) \1


MariaDB와 MySQL에서는 두 개( \\ )를 사용한다.




문자마다 매번 \를 사용하면 알아보기가 힘들어지기 때문에,

Perl, JAVA는 '\Q'와 '\E'를 사용해 이스케이프처리를 한 번에 할 수 있다.


예제 ( Examples )

SQL> SELECT REGEXP_SUBSTR( '$999', '\$999' ) AS RESULT FROM DUAL;

RESULT
--------------------
$999

SQL> SELECT REGEXP_SUBSTR( 'Hi ^^', 'Hi \^\^' ) AS RESULT FROM DUAL;

RESULT
--------------------
Hi ^^

SQL> SELECT REGEXP_SUBSTR( 'Mr.Kim', 'Mr\.Kim' ) AS RESULT FROM DUAL;

RESULT
--------------------
Mr.Kim

SQL> SELECT REGEXP_SUBSTR( '\n means ''new line''', '\\.*' ) AS RESULT FROM DUAL;

RESULT
--------------------
\n means 'new line'

  • <back_slash>만 있는 경우
    < Oracle >
    SQL> SELECT REGEXP_SUBSTR( 'SUNJE', '\' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    NULL
    
    SQL> SELECT REGEXP_COUNT( 'SUNJE', '\' ) AS RESULT FROM DUAL;
    
        RESULT
    ----------
             6
    
    
    < PostgreSQL >
    postgres=# SELECT REGEXP_MATCHES( 'SUNJE', '\', 'g' ) AS RESULT;
    ERROR:  invalid regular expression: invalid escape \ sequence
    
    < MySQL >
    mysql> SELECT REGEXP_SUBSTR( 'SUNJE', '\\' ) AS RESULT;
    ERROR 3689 (HY000): Unrecognized escape sequence in regular expression.
    
    
    < MariaDB >
    MariaDB [test]> SELECT REGEXP_SUBSTR( 'SUNJE', '\\' ) AS RESULT;
    ERROR 1139 (42000): Got error '\ at end of pattern at offset 1' from regexp
    
    
  • <back_slash> 뒤에 일반 문자가 있는 경우
    SQL> SELECT REGEXP_SUBSTR( 'yo', '\yo' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    yo
    
    SQL> SELECT REGEXP_SUBSTR( 'abc', '\a\b\c' ) AS RESULT FROM DUAL;
    
    RESULT
    --------------------
    abc
    
    
  • <back_slash> 뒤에 숫자가 있는 경우
    SQL> SELECT REGEXP_SUBSTR( '123', '\123' ) AS RESULT FROM DUAL;
    SELECT REGEXP_SUBSTR( '123', '\123' ) AS RESULT FROM DUAL
                                 *
    ERROR at line 1:
    ORA-12727: invalid back reference in regular expression
    
    이스케이프 뒤의 숫자는 허용하지 않는다.
    



블로그 이미지

차트

소소한 일상 C코드 DB 항상 행복하게^-^★

,

헤더파일 : MultiProcessWithSemaphore.h

/*******************************************************************************
 * MultiProcessWithSemaphore.h
 *
 *
 *
 * IDENTIFICATION & REVISION
 *        $Id$
 *
 * NOTES
 *
 *
 ******************************************************************************/

/**
 * @file MultiProcessWithSemaphore.h
 * @brief 세마포어를 이용한 멀티 프로세스 큐
 *        헤더파일
 */


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#include <time.h>


#define KEY_ID          9300
#define SIZE            8192
#define PROCESS_COUNT   10
#define DATA_MAX_COUNT  5

#define STL_SUCCESS     0
#define STL_FAILURE     1


#define STL_TRY_THROW( aExpression, aLabel )    \
    do                                          \
    {                                           \
        if( !(aExpression) )                    \
        {                                       \
            goto aLabel;                        \
        }                                       \
    } while( 0 )


#define STL_CATCH( aLabel )                     \
    goto STL_FINISH_LABEL;                      \
    aLabel:


#define STL_FINISH                              \
    STL_FINISH_LABEL:


typedef struct qNode
{
    int mData;

    struct qNode * mPrevNode;
    struct qNode * mNextNode;
} qNode;


typedef struct qQueue
{
    qNode * mFrontNode;
    qNode * mRearNode;
} qQueue;


typedef struct  qStruct
{
    qQueue  mQueue;
    void  * mShmAddr;
    int     mCount;
    sem_t   mSemaphore;
} qStruct;


void * qInitialize( qStruct * aStruct );


void * qEnqueue( qStruct * aStruct,
                 int       aProcessId );


void * qDequeue( qStruct * aStruct,
                 int       aProcessId );


소스파일 : MultiProcessWithSemaphore.c

/*******************************************************************************
 * MultiProcessWithSemaphore.c
 *
 *
 *
 * IDENTIFICATION & REVISION
 *        $Id$
 *
 * NOTES
 *
 *
 ******************************************************************************/

/**
 * @file MultiProcessWithSemaphore.c
 * @brief 세마포어를 이용한 멀티 프로세스 큐
 */


#include "MultiProcessWithSemaphore.h"


void * gShmAddrStart;


int main()
{
    pid_t  sProcessId[PROCESS_COUNT];

    void * sShmAddr   = NULL;


    int sShmId        = 0;
    int sIsDetachShm  = 0;
    int sIsRemoveShm  = 0;
    int sRepeatCount  = 0;
    int sStatus       = 0;

    int sStructSize   = 0;
    int sNodeSize     = 0;

    qStruct * sStruct = NULL;

    
    printf("+-----------------------------------+\n");
    printf("| [SYSTEM] :: program is Started... |\n");
    printf("+-----------------------------------+\n");


    /*
     * Initialize
     */


    /* 공유 메모리 생성 */
    sShmId = shmget( KEY_ID,
                     SIZE,
                     IPC_CREAT | 0666 );

    /* 공유 메모리 생성 실패 확인 */
    STL_TRY_THROW( sShmId != -1,
                   RAMP_ERROR_01 );

    printf("공유 메모리를 생성하였습니다.\n");


    /* 공유 메모리 attach */
    gShmAddrStart = shmat( sShmId,
                           (void *)0,
                           0 );

    /* attach 실패 확인 */
    STL_TRY_THROW( gShmAddrStart != (void *)-1,
                   RAMP_ERROR_02 );

    printf("공유 메모리를 attach 하였습니다.\n");

    
    /*
     * attach한 shared memory 주소로 구조체를 캐스팅
     *
     *  < SHARED MEMORY >
     *  +---------+-------------------------------------------------------
     *  | sStruct |
     *  +---------+-------------------------------------------------------
     *  ^
     *  gShmAddrStart
     *  
     */
    
    sStruct = (qStruct *)gShmAddrStart;

    /* 구조체 sStruct 초기화 */
    qInitialize( sStruct );

    /* 각 구조체들의 크기 */
    sStructSize = sizeof( qStruct );
    sNodeSize   = sizeof( qNode );

    /* ( shared memory 주소값 ) + ( 구조체 크기 )값을 구조체 멤버에 저장 */
    sStruct->mShmAddr = gShmAddrStart + sStructSize;

    
    /*
     * DO
     */


    for( sRepeatCount = 0; sRepeatCount < PROCESS_COUNT; sRepeatCount++ )
    {
        sProcessId[sRepeatCount] = fork();


        if( sProcessId[sRepeatCount] > 0 )
        {
            /* 부모 프로세스 */
            /* do nothing */
        }
        else if( sProcessId[sRepeatCount] == 0 )
        {
            /* 자식 프로세스 */
            /* 자식 프로세스 절반은 enqueue, 절반은 dequeue */
            if( sRepeatCount % 2 == 0 )
            {
                /* Enqueue */
                qEnqueue( sStruct, sRepeatCount );
            }
            else
            {
                /* Dequeue */
                qDequeue( sStruct, sRepeatCount );
            }
            
            exit( STL_SUCCESS );
        }
        else
        {
            /* fork 실패 */
            STL_TRY_THROW( STL_SUCCESS,
                           RAMP_ERROR_04 );
        }
    }



    /*
     * Finalize
     */


    /* 부모 프로세스의 wait 호출 */
    for( sRepeatCount = 0; sRepeatCount < PROCESS_COUNT; sRepeatCount++ )
    {
        sProcessId[sRepeatCount] = wait( &sStatus );
    }
    
    
    /* 세마포어 종료 */
    sem_destroy( &sStruct->mSemaphore );

    printf("세마포어를 종료하였습니다.\n");
    
    /* 공유 메모리 detach */
    sIsDetachShm = shmdt( gShmAddrStart );

    /* detach 실패 확인 */
    STL_TRY_THROW( sIsDetachShm != -1,
                   RAMP_ERROR_03 );
    
    printf("공유 메모리를 detach 하였습니다.\n");
    


    printf("+-----------------------------------+\n");
    printf("| [SYSTEM] :: program is Exited...  |\n");
    printf("+-----------------------------------+\n");
    

    
    return STL_SUCCESS;

    
    STL_CATCH( RAMP_ERROR_01 )
    {
        printf("[ERROR-01] :: cannot get shared memory which key '%d'.\n", KEY_ID );
    }

    STL_CATCH( RAMP_ERROR_02 )
    {
        printf("[ERROR-02] :: cannot attach shared memory which key '%d'.\n", KEY_ID );
    }

    STL_CATCH( RAMP_ERROR_03 )
    {
        printf("[ERROR-03] :: cannot detach shared memory which key '%d'.\n", KEY_ID );
    }

    STL_CATCH( RAMP_ERROR_04 )
    {
        printf("[ERROR-04] :: cannot create child process.\n");
    }

    
    STL_FINISH;
    

    return STL_FAILURE;
}


void * qInitialize( qStruct * aStruct )
{
    aStruct->mQueue.mFrontNode = NULL;
    aStruct->mQueue.mRearNode  = NULL;
    
    aStruct->mShmAddr = NULL;
    aStruct->mCount   = 0;

    /* 세마포어 초기화 */
    sem_init( &aStruct->mSemaphore,
              1,
              1 );
}


void * qEnqueue( qStruct * aStruct,
                 int       aProcessId )
{
    int     sRepeatCount = 0;
    int     sNodeSize    = 0;

    qNode * sNewNode     = NULL;

    sNodeSize = sizeof( qNode );

    /* rand() */
    srand( aProcessId );

    while( sRepeatCount < DATA_MAX_COUNT )
    {
        /* semaphore lock */
        sem_wait( &aStruct->mSemaphore );

        if( aStruct->mCount >= PROCESS_COUNT )
        {
            /* printf("queue is full!\n"); */
        }
        
        else
        {
            /*
             *  < SHARED MEMORY >
             *  +---------+----------+--------------------------------------------
             *  | sStruct | sNewNode |                   
             *  +---------+----------+--------------------------------------------
             *            ^
             *            mShmAddr
             *  
             */
            
            sNewNode = (qNode *)aStruct->mShmAddr;
            aStruct->mShmAddr += sNodeSize;


            /* 두 자리 임의의 수를 sNewNode의 mData에 저장 */
            sNewNode->mData = rand()%90 + 10;
            sNewNode->mNextNode = NULL;
        
            if( aStruct->mCount == 0 )
            {
                aStruct->mQueue.mFrontNode = sNewNode;
                sNewNode->mPrevNode = NULL;
            }
            else
            {
                aStruct->mQueue.mRearNode->mNextNode = sNewNode;
                sNewNode->mPrevNode = aStruct->mQueue.mRearNode;
            }

            aStruct->mQueue.mRearNode = sNewNode;
            aStruct->mCount++;

            printf("[#%3d][ENQUEUE_DATA] : %d  QUEUE STATUS [ %2d/%d ]\n",
                   aProcessId,
                   aStruct->mQueue.mRearNode->mData,
                   aStruct->mCount,
                   PROCESS_COUNT );

            sRepeatCount++;
        }

        /* semaphore unlock */
        sem_post( &aStruct->mSemaphore );
        usleep(50);
    }
}


void * qDequeue( qStruct * aStruct,
                 int       aProcessId )
{
    int    sRepeatCount = 0;
    int    sOutputData  = 0;
    int    sStructSize  = 0;
    int    sNodeSize    = 0;
    
    void * sShmAddr     = NULL;

    sStructSize = sizeof( qStruct );
    sNodeSize   = sizeof( qNode );
    

    while( sRepeatCount < DATA_MAX_COUNT )
    {
        sem_wait( &aStruct->mSemaphore );

        if( aStruct->mCount == 0 )
        {
            /* printf("queue is empty!\n"); */
        }

        else
        {
            sOutputData = aStruct->mQueue.mFrontNode->mData;

            if( aStruct->mCount == 1 )
            {
                aStruct->mQueue.mFrontNode = NULL;
                aStruct->mQueue.mRearNode  = NULL;
                aStruct->mCount            = 0;
            }

            else
            {
                aStruct->mQueue.mFrontNode = aStruct->mQueue.mFrontNode->mNextNode;
                aStruct->mQueue.mFrontNode->mPrevNode = NULL;
                aStruct->mCount--;
            }

            printf("[#%3d][DEQUEUE_DATA] : %d  QUEUE STATUS [ %2d/%d ]\n",
                   aProcessId,
                   sOutputData,
                   aStruct->mCount,
                   PROCESS_COUNT );

            sRepeatCount++;
        }

        sem_post( &aStruct->mSemaphore );
        usleep(50);
    }
}


공부/코딩연습 등의 이유로 얼마든지 퍼가셔도 좋습니다.


하지만 라인마다 의미를 파악하지 않고 무작정 복사 붙여넣기는

아무것도 남지 않습니다.


또한 댓글로 궁금하신 라인 등 얼마든지 물어보시면 

바로바로 대답해드리겠습니다 :)


공부를 게을리하지 맙시다! 


블로그 이미지

차트

소소한 일상 C코드 DB 항상 행복하게^-^★

,

POSIX BRE( Basic Regular Expression )

  1. ^
  2. $
  3. .
  4. *
  5. \
  6. (
  7. {
  8. [




4. * ( Asterisk )

구문 ( Syntax )

<asterisk> ::= *
  • 사용 예
    <pattern_expr><asterisk>
    

설명 ( Description )

  • 0 or MORE
  • 수량자(quantifier)로, <asterisk> 앞의 <pattern_expr>이 없거나 하나 이상 있음을 의미한다.
    • ex) a* =>  , a, aa, aaa, ...
  • <asterisk>만 있는 경우
    • ex) *
    • 결과
      • Oracle : zero-length match
      • PostgreSQL, MySQL, MariaDB : error 처리
  • zero-length match가 발생할 수 있다. ( 이에 대해선 다음에 다시 설명 )


수량자(quantifier)란?

수량자는 주어진 <pattern_expr>의 수량(quantity)을 지정해주는 메타문자이다.
일반적으로 수량자는가능한 많은 문자와 매칭 시키려는 성질을 가지고 있다.


예제 ( Examples )

SQL> SELECT REGEXP_SUBSTR( 'aaaaabbb', 'a*' ) AS RESULT FROM DUAL;

RESULT
--------------------
aaaaa

SQL> SELECT REGEXP_SUBSTR( 'abababc', '(ab)*' ) AS RESULT FROM DUAL;

RESULT
--------------------
ababab

SQL> SELECT REGEXP_SUBSTR( 'knight', '.*knight' ) AS RESULT FROM DUAL;

RESULT
--------------------
knight

SQL> SELECT REGEXP_SUBSTR( 'GOLDILOCKS', 'GOLD(.*)' ) AS RESULT FROM DUAL;

RESULT
--------------------
GOLDILOCKS

SQL> SELECT REGEXP_SUBSTR( 'abc', 'z*' ) AS RESULT FROM DUAL;

RESULT
--------------------
NULL

SQL> SELECT REGEXP_COUNT( 'abc', 'z*' ) AS RESULT FROM DUAL;

    RESULT
----------
         4

  • <asterisk>만 있는 경우
    < Oracle >
    SQL> SELECT REGEXP_SUBSTR( 'ab', '*' ) AS RESULT FROM DUAL;
    
    RESULT
    ------------------------------
    NULL
    
    SQL> SELECT REGEXP_COUNT( 'ab', '*' ) AS RESULT FROM DUAL;
    
        RESULT
    ----------
             3
    
    
    < PostreSQL >
    postgres=# SELECT REGEXP_MATCHES( 'ab', '*', 'g' ) AS RESULT;
    ERROR:  invalid regular expression: quantifier operand invalid
    
    
    < MySQL >
    mysql> SELECT REGEXP_SUBSTR( 'ab', '*' ) AS RESULT;
    ERROR 3688 (HY000): Syntax error in regular expression on line 1, character 1.
    
    
    < MariaDB >
    MariaDB [test]> SELECT REGEXP_SUBSTR( 'ab', '*' ) AS RESULT;
    ERROR 1139 (42000): Got error 'nothing to repeat at offset 0' from regexp
    
    


블로그 이미지

차트

소소한 일상 C코드 DB 항상 행복하게^-^★

,

POSIX BRE( Basic Regular Expression )

  1. ^
  2. $
  3. .
  4. *
  5. \
  6. (
  7. {
  8. [




3. . ( Period )

구문 ( Syntax )

<period> ::= .

설명 ( Description )

  • 임의의 한 문자를 의미한다.
  • newline 문자( ASCII(10)인 Line Feed(\n) ), NULL은 매칭하지 않는다.


예제 ( Examples )

SQL> SELECT REGEXP_SUBSTR( 'A', '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
A

SQL> SELECT REGEXP_SUBSTR( 'a', '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
a

SQL> SELECT REGEXP_SUBSTR( '7', '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
7

SQL> SELECT REGEXP_SUBSTR( '%', '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
%

SQL> SELECT REGEXP_SUBSTR( '_', '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
_

SQL> SELECT REGEXP_SUBSTR( CHR(10), '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
NULL

SQL> SELECT REGEXP_COUNT( CHR(10), '.' ) AS RESULT FROM DUAL;

    RESULT
----------
         0

SQL> SELECT REGEXP_SUBSTR( NULL, '.' ) AS RESULT FROM DUAL;

RESULT
--------------------
NULL

SQL> SELECT REGEXP_COUNT( NULL, '.' ) AS RESULT FROM DUAL;

    RESULT
----------
NULL


블로그 이미지

차트

소소한 일상 C코드 DB 항상 행복하게^-^★

,