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 항상 행복하게^-^★

,

POSIX BRE( Basic Regular Expression )

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



2. $ ( Dollar )

구문 ( Syntax )

<dollar> ::= $
  • 사용 예
    <dollar>
    
    <pattern_expr><dollar>
    
    <dollar><pattern_expr>
    
    <pattern_expr><dollar><pattern_expr>
    

설명 ( Description )

  • source string의 끝을 의미한다.
  • 일반적으로 <dollar> 앞에 <pattern_expr>을 입력하여 사용한다.
    • ex) abc$
  • <dollar> 만 있는 경우, source string의 맨 뒤를 매칭한다. ( zero-length match )
    • ex) $
  • <dollar> 뒤에 <pattern_expr>이 있는 경우, 어떤 source string과도 매칭하지 않는다.
    • ex) $a
    • 예외
      • ex) ab$c* <=> ab$
      • ex) $c* <=> $


별다른 옵션이 없다면 source string의 끝지점을 매칭하지만, 

multiline mode 옵션이 주어지면 source string의 각 라인 끝지점들을 매칭한다. ( 이 경우, 라인의 기준은 ASCII(10)인 Line Feed(\n)이다. )


예제 ( Examples )

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

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

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

    RESULT
----------
         1

SQL> SELECT REGEXP_SUBSTR( 'abc', '$c' ) AS RESULT FROM DUAL;

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

SQL> SELECT REGEXP_COUNT( 'abc', '$c' ) AS RESULT FROM DUAL;

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

SQL> SELECT REGEXP_SUBSTR( 'abc', '.$c*' ) AS RESULT FROM DUAL;

RESULT
--------------------
c

SQL> SELECT REGEXP_SUBSTR( 'abc', 'c$' ) AS RESULT FROM DUAL;

RESULT
--------------------
c

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

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

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

RESULT
--------------------
f

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

    RESULT
----------
         1

SQL> SELECT REGEXP_SUBSTR( 'abc'||CHR(10)||'def', '.$', 1, 1, 'm' ) AS RESULT FROM DUAL;

RESULT
--------------------
c

SQL> SELECT REGEXP_SUBSTR( 'abc'||CHR(10)||'def', '.$', 1, 2, 'm' ) AS RESULT FROM DUAL;

RESULT
--------------------
f

SQL> SELECT REGEXP_COUNT( 'abc'||CHR(10)||'def', '$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         2

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

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

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

    RESULT
----------
         1

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

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

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

    RESULT
----------
         1

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

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

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

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

SQL> SELECT REGEXP_SUBSTR( 'a'||CHR(10)||CHR(10), '.$', 1, 1, 'm' ) AS RESULT FROM DUAL;

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

SQL> SELECT REGEXP_SUBSTR( 'a'||CHR(10)||CHR(10), '.$', 1, 2, 'm' ) AS RESULT FROM DUAL;

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

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10), '.$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a', '.$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10), '.$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10), '.$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a', '$' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10), '$' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10), '$' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10)||CHR(10), '$' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a', '$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10), '$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         1

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10), '$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         2

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10)||CHR(10), '$', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         3

SQL> SELECT REGEXP_COUNT( 'a'||CHR(10)||CHR(10)||CHR(10)||CHR(10), '$', 1, 'm' ) AS RESULT FROM DUAL;

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


블로그 이미지

차트

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

,

Meta Characters

  • 12가지 메타 문자들의 정의 및 스펙을 기술 ( 소괄호 닫기는 소괄호와 같이 묶었기 때문에 항목은 11개 )
  • BRE의 메타문자, ERE에서 추가된 메타문자 순서로 작성
  • 항목별로 구문( Syntax )설명( Description )예제( Examples )
  • 예제는 Oracle DBMS 18c 버전 기준 REGEXP_SUBSTR() 함수를 사용,
    PostgreSQL, MariaDB, MySQL 에서의 Test와 결과가 다른 것은 명시하였음


'매칭한다 ( Matching )'

str을 매칭한다고 함은, 일치한다가 아니라 source string '안'에 해당 패턴이 '포함'됨을 의미한다.
( When I say a regex "matches" a string, I really mean that it matches in a string. )
즉,

'a' match 'cat' X
'a' match in 'cat' O

( Technically, the regex 'a' doesn't match cat, but matches the 'a' in cat. )
혼동에 주의하자!




POSIX BRE( Basic Regular Expression )

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



1. ^ ( Caret )

구문 ( Syntax )

<caret> ::= ^
  • 사용 예
    <caret>
    
    <caret><pattern_expr>
    
    <pattern_expr><caret>
    
    <pattern_expr><caret><pattern_expr>
    

설명 ( Description )

  • source string의 시작을 의미한다.
  • 일반적으로 <caret> 뒤에 <pattern_expr>을 입력하여 사용한다.
    • ex) ^abc
  • <caret> 만 있는 경우, source string의 맨 앞을 매칭한다. ( zero-length match )
    • ex) ^
  • <caret> 앞에 <pattern_expr>이 있는 경우, 어떤 source string과도 매칭하지 않는다.
    • ex) a^
    • 예외
      • ex) a*^bc <=> ^bc
      • ex) a*^ <=> ^


별다른 옵션이 없다면 source string의 시작지점을 매칭하지만, 

multiline mode 옵션이 주어지면 source string의 각 라인 시작지점들을 매칭한다. ( 이 경우, 라인의 기준은 ASCII(10)인 Line Feed(\n)이다. )


예제 ( Examples )

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

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

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

    RESULT
----------
         1

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

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

SQL> SELECT REGEXP_COUNT( 'abc', 'a^' ) AS RESULT FROM DUAL;

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

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

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

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

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

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

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

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

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

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

    RESULT
----------
         1

SQL> SELECT REGEXP_SUBSTR( 'abc'||CHR(10)||'def', '^.', 1, 1, 'm' ) AS RESULT FROM DUAL;

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

SQL> SELECT REGEXP_SUBSTR( 'abc'||CHR(10)||'def', '^.', 1, 2, 'm' ) AS RESULT FROM DUAL;

RESULT
--------------------
d

SQL> SELECT REGEXP_COUNT( 'abc'||CHR(10)||'def', '^', 1, 'm' ) AS RESULT FROM DUAL;

    RESULT
----------
         2


블로그 이미지

차트

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

,

헤더파일 : MultiThreadWithSignal.h

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

/**
 * @file MultiThreadWithSignal.h
 * @brief 다중 연결 리스트( Doubly Linked List ) 큐
 *        Enqueue와 Dequeue를 스레드를 통해 진행
 *        헤더파일
 */


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>


#define THREAD_COUNT    100
#define DATA_MAX_COUNT  2000


/* 큐를 이루는 노드 구조체 */
typedef struct qNode
{
    int             mData;             /* Data */
    int             mEnqueueThreadId;  /* 데이터를 준 스레드 ID */
    
    struct qNode  * mPrevNode;         /* 이전 Node */
    struct qNode  * mNextNode;         /* 다음 Node */
} qNode;


/* 큐 구조체 */
typedef struct qQueue
{
    qNode  * mFrontNode;      /* Dequeue */
    qNode  * mRearNode;       /* Enqueue */
    
    int      mCount;          /* 노드 갯수 */
} qQueue;


/* 스레드 생성 시 인자로 넘겨주는 구조체 */
typedef struct qArgPthread
{
    qQueue  * mQueue;         /* Queue */
    int       mThreadId;      /* 스레드 ID */
} qArgPthread;


/* Initialize Queue */
void  qInitQueue( qQueue * aQueue );


/* Enqueue */
void  * qEnqueue( void * aArgPthread );


/* Dequeue */
void  * qDequeue( void * aArgPthread );


소스파일 : MultiThreadWithSignal.c

/*******************************************************************************
 * MultiThreadWithSignal.c
 *
 * Copyright (c) 2011, SUNJESOFT Inc.
 *
 *
 * IDENTIFICATION & REVISION
 *        $Id$
 *
 * NOTES
 *
 *
 ******************************************************************************/

/**
 * @file MultiThreadWithSignal.c
 * @brief 다중 연결 리스트( Doubly Linked List ) 큐
 *        Enqueue와 Dequeue를 스레드를 통해 진행
 *        Enqueue 스레드가 enqueue 이후 signal을 전송,
 *        Dequeue 스레드가 signal을 받고 dequeue를 수행
 *        다시 Enqueue 스레드에게 작업을 마친 flag를 넘긴다.
 */


#include "MultiThreadWithSignal.h"


/* Global Mutex & Condition Variable */
pthread_mutex_t  gMutexForThread;
pthread_mutex_t  gMutexForEnqDeq[THREAD_COUNT];

pthread_cond_t   gCondition[THREAD_COUNT];


/* Flag Variables */
int  gMainFlag;
int  gFlagForThread[THREAD_COUNT];
int  gFlagForEnqDeq[THREAD_COUNT];


int main()
{
    pthread_t      sEnqueueThread[THREAD_COUNT];      /* THREAD_COUNT 만큼의 Enqueue 스레드 선언 */
    pthread_t      sDequeueThread[THREAD_COUNT];      /* THREAD_COUNT 만큼의 Dequeue 스레드 선언 */
    
    qArgPthread  * sArgEnqueueThread[THREAD_COUNT];   /* THREAD_COUNT 만큼의 인자로 넘겨줄 구조체 */
    qArgPthread  * sArgDequeueThread[THREAD_COUNT];   /* THREAD_COUNT 만큼의 인자로 넘겨줄 구조체 */

    qQueue       * sQueue              = NULL;

    int            sIsCreatedThread    = 0;           /* 스레드가 Create되었는지 여부를 알기 위한 변수 */
    int            sIsJoinedThread     = 0;           /* 스레드가 Join되었는지 여부를 알기 위한 변수 */
    int            sReturnValue        = 0;           /* 스레드가 Join 수행 시 반환하는 값 */
    int            sCountThread        = 0;           /* 스레드 개수, 각종 for문의 정수형 변수 */
    int            sDoubleThreadCount  = 0;

    sQueue  = (qQueue *)malloc( sizeof( qQueue ) );
    
    sDoubleThreadCount = THREAD_COUNT * 2;            /* THREAD_COUNT의 두배 */

    
    /*
     * Initialize
     */

    pthread_mutex_init( &gMutexForThread, NULL );

    for( sCountThread = 0; sCountThread < THREAD_COUNT; sCountThread++ )
    {
        /* Mutex */        
        pthread_mutex_init( &gMutexForEnqDeq[sCountThread], NULL );

        /* Condition Value */
        pthread_cond_init( &gCondition[sCountThread], NULL );

        /* Flags */
        gFlagForThread[sCountThread] = 0;
        gFlagForEnqDeq[sCountThread] = 0;
    }

    gMainFlag = 0;            /* Flag */
    
    qInitQueue( sQueue );     /* 큐 sQueue 초기화 */

    
    /* 스레드 Mutex Lock */
    pthread_mutex_lock( &gMutexForThread );

    
    /*
     * 스레드 Create
     */


    /* Enqueue 스레드 */
    for( sCountThread = 0; sCountThread < THREAD_COUNT; sCountThread++ )
    {
        sArgEnqueueThread[sCountThread] = (qArgPthread *)malloc( sizeof( qArgPthread ) );

        /* 인자의 스레드 ID는 0, 1, ..., n */
        sArgEnqueueThread[sCountThread]->mQueue     = sQueue;
        sArgEnqueueThread[sCountThread]->mThreadId  = sCountThread;
        
        sIsCreatedThread = pthread_create( &sEnqueueThread[sCountThread],
                                           NULL,
                                           &qEnqueue,
                                           (void *)sArgEnqueueThread[sCountThread] );

        if( sIsCreatedThread != 0 )
        {
            printf("[ERROR-001] :: cannot create thread.\n");
        }
    }
    
    /* Dequeue 스레드 */
    for( sCountThread = 0; sCountThread < THREAD_COUNT; sCountThread++ )
    {
        sArgDequeueThread[sCountThread] = (qArgPthread *)malloc( sizeof( qArgPthread ) );

        /* 인자의 스레드 ID는 0, 1, ..., n */
        sArgDequeueThread[sCountThread]->mQueue     = sQueue;
        sArgDequeueThread[sCountThread]->mThreadId  = sCountThread;
        
        sIsCreatedThread = pthread_create( &sDequeueThread[sCountThread],
                                           NULL,
                                           &qDequeue,
                                           (void *)sArgDequeueThread[sCountThread] );

        if( sIsCreatedThread != 0 )
        {
            printf("[ERROR-001] :: cannot create thread.\n");
        }
    }

    /* 모든 스레드 생성 후 플래그 값 확인 */
    while( gMainFlag < sDoubleThreadCount )
    {
        gMainFlag = 0;
        for( sCountThread = 0; sCountThread < THREAD_COUNT; sCountThread++ )
        {
            gMainFlag += gFlagForThread[sCountThread];
        }
        sleep(0);
    }

    /* 스레드 Mutex Unlock */
    pthread_mutex_unlock( &gMutexForThread );
    
    /*
     * 스레드 Join
     */

    for( sCountThread = 0; sCountThread < THREAD_COUNT; sCountThread++ )
    {
        /* Enqueue 스레드 */
        sIsJoinedThread = pthread_join( sEnqueueThread[sCountThread],
                                        (void **)&sReturnValue );

        if( sIsJoinedThread != 0 )
        {
            printf("[ERROR-002] :: cannot join enqueue thread.\n");
        }

        
        /* Dequeue 스레드 */
        sIsJoinedThread = pthread_join( sDequeueThread[sCountThread],
                                        (void **)&sReturnValue );

        if( sIsJoinedThread != 0 )
        {
            printf("[ERROR-002] :: cannot join dequeue thread.\n");
        }
        
    }

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



/* Initialize Queue */
void qInitQueue( qQueue * aQueue )
{
    aQueue->mFrontNode  = NULL;
    aQueue->mRearNode   = NULL;
    aQueue->mCount      = 0;

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

}



/* Enqueue */
void  * qEnqueue( void * aArgPthread )
{
    qArgPthread * sArgPthread   = NULL;
    qQueue      * sQueue        = NULL;
    qNode       * sNewNode      = NULL;

    int           sInputData    = 0;
    int           sRepeatCount  = 0;
    int           sThreadId     = 0;
    /* int           sMaxBuff      = 0; */

    sArgPthread = (qArgPthread *)aArgPthread;

    sQueue      = sArgPthread->mQueue;
    sThreadId   = sArgPthread->mThreadId;

    /* sMaxBuff    = DATA_MAX_COUNT * 2; */

    printf("[#%3d][ENQUEUE_THREAD] is ready.\n", sThreadId );
    gFlagForThread[sThreadId] += 1;
    
    while( sRepeatCount < DATA_MAX_COUNT )
    {
        /* Dequeue 스레드의 준비를 기다린다. */
        while( gFlagForEnqDeq[sThreadId] == 0 )
        {
            sleep(0);
        }
        
        /* 스레드 Mutex Lock */
        pthread_mutex_lock( &gMutexForThread );

        sNewNode = (qNode *)malloc( sizeof( qNode ) );
            
        if( sQueue->mCount >= THREAD_COUNT /* sMaxBuff */ )
        {
            /* printf("[THREAD_%d]\n[ERROR-003] :: queue is full. [ %d/%d ]\n\n", */
            /*        sThreadId, */
            /*        DATA_MAX_COUNT, */
            /*        DATA_MAX_COUNT ); */
        }
        else
        {
            sInputData                  = rand() % 90 + 10; /* 임의의 데이터 값을 두자리 수로 고정 */
            sNewNode->mData             = sInputData;
            sNewNode->mNextNode         = NULL;
            sNewNode->mEnqueueThreadId  = sThreadId;

            printf("[#%3d][ENQUEUE_THREAD] Enqueue DATA : %d( %d/%d ) QUEUE STATUS : [ %d/%d ]\n",
                   sThreadId,
                   sInputData,
                   sRepeatCount+1,
                   DATA_MAX_COUNT,
                   sQueue->mCount+1,
                   THREAD_COUNT /* sMaxBuff */ );

            if( sQueue->mCount == 0 )
            {
                sQueue->mFrontNode   = sNewNode;
                sNewNode->mPrevNode  = NULL;
            }
            else
            {
                sQueue->mRearNode->mNextNode  = sNewNode;
                sNewNode->mPrevNode           = sQueue->mRearNode;
            }

            sQueue->mRearNode  = sNewNode;
            sQueue->mCount++;

            sRepeatCount++;
        }

        /* 스레드 Mutex Unlock */
        pthread_mutex_unlock( &gMutexForThread );

        /* Enqueue Mutex Lock */
        pthread_mutex_lock( &gMutexForEnqDeq[sThreadId] );

        gFlagForEnqDeq[sThreadId] = 0; /* 0으로 다시 초기화 */
        
        /* Dequeue 스레드에게 시그널 */
        pthread_cond_signal( &gCondition[sThreadId] );

        /* Enqueue Mutex Unlock */
        pthread_mutex_unlock( &gMutexForEnqDeq[sThreadId] );

        /* if( sRepeatCount%5 == 0 ) */
        /* { */
        usleep(50);
        /* } */
    }
}





/* Dequeue */
void  * qDequeue( void * aArgPthread )
{
    qArgPthread * sArgPthread   = NULL;
    qQueue      * sQueue        = NULL;

    int       sOutputData       = 0;
    int       sRepeatCount      = 0;
    int       sThreadId         = 0;
    int       sEnqueueThreadId  = 0;
    /* int       sMaxBuff          = 0; */

    sArgPthread = (qArgPthread *)aArgPthread;
    
    sQueue     = sArgPthread->mQueue;
    sThreadId  = sArgPthread->mThreadId;

    /* sMaxBuff   = DATA_MAX_COUNT * 2; */

    printf("[#%3d][DEQUEUE_THREAD] is ready.\n", sThreadId );
    gFlagForThread[sThreadId] += 1;

    while( sRepeatCount < DATA_MAX_COUNT )
    {
        /* Mutex Lock */
        pthread_mutex_lock( &gMutexForEnqDeq[sThreadId] );

        /* Enqueue 스레드에게 준비가 되었음을 알림 */
        gFlagForEnqDeq[sThreadId] = 1;

        /* Enqueue 까지 기다린다. */
        pthread_cond_wait( &gCondition[sThreadId], &gMutexForEnqDeq[sThreadId] );

        /* Mutex Unlock */
        pthread_mutex_unlock( &gMutexForEnqDeq[sThreadId] );
        
        /* 스레드 Mutex Lock */
        pthread_mutex_lock( &gMutexForThread );

        if( sQueue->mCount == 0 )
        {
            /* printf("[THREAD_%d]\n[ERROR-004] :: queue is empty. [ 0/%d ]\n\n", */
            /*        sThreadId, */
            /*        DATA_MAX_COUNT ); */
        }
        else
        {
            sOutputData       = sQueue->mFrontNode->mData;
            sEnqueueThreadId  = sQueue->mFrontNode->mEnqueueThreadId;

            printf("[#%3d][DEQUEUE_THREAD] Dequeue DATA : %d( %d/%d ) QUEUE STATUS : [ %d/%d ] data by [#%3d][ENQUEUE_THREAD]\n",
                   sThreadId,
                   sOutputData,
                   sRepeatCount+1,
                   DATA_MAX_COUNT,
                   sQueue->mCount-1,
                   THREAD_COUNT /* sMaxBuff */,
                   sEnqueueThreadId );

            if( sQueue->mCount == 1 )
            {
                free( sQueue->mFrontNode );
                sQueue->mFrontNode  = NULL;
                sQueue->mRearNode   = NULL;
                sQueue->mCount      = 0;
            }
            else
            {
                sQueue->mFrontNode = sQueue->mFrontNode->mNextNode;
                free( sQueue->mFrontNode->mPrevNode );
                sQueue->mFrontNode->mPrevNode = NULL;
                sQueue->mCount--;
            }

            sRepeatCount++;
        }

        /* 스레드 Mutex Unlock */
        pthread_mutex_unlock( &gMutexForThread );

        /* if( sRepeatCount%5 == 0 ) */
        /* { */
            usleep(50);
        /* } */

    }

}



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


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

아무것도 남지 않습니다.


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

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


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


블로그 이미지

차트

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

,

REGULAR EXPRESSION ( 정규 표현식 )


Basic Concepts

What is Regular Expression?

정규 표현식이란, 특정한 규칙을 가진 문자열의 집합을 표현하는데 사용하는 형식 언어이다.

  • 즉 쉽게 말해 문자열을 다루는 하나의 언어이다.

주로 Programming Language나 Text Editor 등에서
특정 문자열의 검색, 치환 등의 처리를 위한 용도로 사용된다.


How to Express

정규 표현식은 언어마다 문법이 다르기 때문에, 표준을 먼저 정의할 필요가 있다.
크게 나누면 표준인 POSIX의 BRE와 ERE가 있고, 여기서 문법을 확장한 Perl 호환 정규 표현식으로 나뉜다.

  • 표준
    • POSIX1) 기반의
      • 기본 정규 표현식( BRE : Basic Regular Expression )
      • 확장 정규 표현식( ERE : Extended Regular Expression )
  • 비표준
    • Perl 호환 정규 표현식


1) POSIX란?

이식 가능 운영 체제 인터페이스( Portable Operating System Interface )의 약자로,
서로 다른 UNIX OS의 공통 API를 정리해 이식성이 높은 유닉스 응용 프로그램을 개발하기 위해
IEEE가 책정한 애플리케이션 인터페이스 규격이다.




이러한 정규 표현식에서 사용하는 기호들을 메타문자( Meta Character )라 한다.
메타문자는 표현식 내에서 특정한 의미를 갖는 문자를 일컫는다.
BRE 및 ERE의 메타문자 12개 존재한다.


no.POSIX BRE syntaxadded POSIX ERE syntax
1.^
2.$
3..
4.*
5.\
6.(
7.)
8.{
9.[
10.+
11.?
12.|

  • 종료 대괄호 ]나 하이픈 -은 대괄호 [ 뒤에 올 경우에만 메타문자로 인식한다.
  • 종료 중괄호 }는 { 뒤에 올 경우에만 메타문자로 인식한다.
  • 반면 소괄호 )는 대괄호, 중괄호와 달리 메타문자로 인식하는데,
    소괄호는 무조건 ()가 쌍으로 존재하지 않으면 에러처리하기 때문에
    메타문자로 다룬다.
  • 이러한 메타문자들 앞에 백슬래시 \를 사용하면 일반 문자로 인식할 수 있다.


블로그 이미지

차트

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

,

근래 리눅스 환경은 윈도우즈 환경과 많이 다르지 않지만 (다르...죠)

적응하는데 도움이 되었던 키워드, 명령어 위주로 정리를 했습니다.


LINUX Terminal

Group

  • groups [ username ] : 사용자가 포함된 그룹을 나열
    $ groups anbo
    anbo : anbo sudo
    
  • groupadd [ groupname ] : 그룹 생성
    $ sudo groupadd group1
    
  • groupdel [ groupname ] : 그룹 삭제
    $ sudo groupdel group1
    
  • gpasswd
    • gpasswd [ groupname ] : 그룹에 암호 설정
      $ sudo gpasswd group1
      group1 그룹의 암호를 바꾸는 중
      새 암호 :
      새 암호를 다시 입력하십시오 :
      
    • gpasswd -r [ groupname ] : 그룹의 암호 제거
    • gpasswd -A [ username ] [ groupname ] : 사용자를 그룹의 관리자로 설정
    • gpasswd -a [ username ] [ groupname ] : 사용자를 그룹에 포함
    • gpasswd -d [ username ] [ groupname ] : 사용자를 그룹에서 제외 


  • ifconfig
    현재 네트워크 하드의 개수 및 ip 관련 정보



EMACS

  • Ctrl + x-f : 파일 열기, 없을 시 새로 생성
  • Ctrl + x-s : 파일 저장
  • Ctrl + x-w : 다른 이름으로 저장
  • Ctrl + g : 명령 취소
  • Ctrl + /, Ctrl + x + u : 실행 취소
  • Ctrl + d, Alt + d : 커서 글자 삭제
  • Ctrl + x-x : 블록 설정 앞뒤 변경
  • Alt + w : 복사( 와 유사 )
  • Ctrl + w : 잘라내기( 와 유사 )
  • Ctrl + y : 붙여넣기( 와 유사 )
  • Ctrl + s : 검색( 아래로 )
  • Ctrl + r : 검색( 위로 )



CSCOPE

  • Ctrl + c + s + [OPTION]
  • OPTIONS
    • s : Find symbol(심볼=변수, 함수, 매크로, 구조체, 들을 찾는다).
    • d : Find global definition.
    • g : Find global definition(alternate binding).
    • G : Find global definition without prompting.
    • c : Find functions calling a function(이 함수를 호출하는 함수를 검색한다).
    • C : Find called functions (list functions called from a function)(이 함수에 의해 호출되는 함수를 검색한다).
    • t : Find text string(텍스트 문자열을 검색한다).
    • e : Find egrep pattern(정규식을 이용해서 소스코드를 검색한다).
    • f : Find a file(특정이름을 포함한 파일을 모두 검색한다).
    • i : Find files #including a file(특정헤더를 포함시키는 모든 소스코드를 검색한다).
    • u : go back to marked up buffer(뒤로 가기).


블로그 이미지

차트

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

,