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

,