NAME

regex - POSIX.2 정규 표현식

DESCRIPTION

POSIX.2에 규정돼 있는 정규 표현식(regular expression, "RE")에는 두 가지 형태가 있다. 신식 RE(대략 egrep의 RE. POSIX.2에서는 "확장" RE라고 함)와 구식 RE(대략 ed(1)의 RE. POSIX.2에서는 "기본" RE라고 함)이다. 구식 RE는 주로 몇몇 오래된 프로그램에 하위 호환성을 위해 남아 있는데 마지막에서 설명한다. POSIX.2에서는 RE 문법과 의미론 일부를 미정으로 남겨두고 있다. "(!)"는 그런 부분들을 어떻게 구현하기로 했는지 나타내며 다른 POSIX.2 구현과 완전히 호환되지는 않을 수도 있다.

(신식) RE 식은 '|'로 구분된 1개(!) 이상의 비어 있지 않은(!) 브랜치다. 그 중 어느 브랜치에라도 일치하면 식에 일치하는 것이다.

브랜치(branch)란 1개(!) 이상의 조각을 이어 붙인 것이다. 첫 번째 조각과 일치하고 이어서 차례로 일치하면 브랜치에 일치하는 것이다.

조각(piece)이란 원자만 있거나 그 뒤에 '*'나 '+', '?', 한계가 1개(!) 붙은 것이다. 원자 뒤에 '*'가 있으면 그 원자와 0번 이상 일치하는 열에 일치한다. 원자 뒤에 '+'가 있으면 그 원자와 1번 이상 일치하는 열에 일치한다. 원자 뒤에 '?'가 있으면 그 원자와 0번 또는 1번 일치하는 열에 일치한다.

한계(bound)란 '{'에 이어서 부호 없는 10진수 정수가 오고, 선택적으로 ','가 오고, 선택적으로 또 다른 부호 없는 10진수 정수가 오고, 항상 마지막에 '}'가 붙은 것이다. 정수는 0에서 RE_DUP_MAX(255(!))까지 내에 있어야 하며 두 개일 때는 첫 번째가 두 번째보다 크지 않아야 한다. 원자 뒤에 정수 i가 있고 쉼표는 없는 한계가 있으면 원자와 정확히 i 번 일치하는 열에 일치한다. 원자 뒤에 정수 i와 쉼표가 있는 한계가 있으면 원자와 i 번 이상 일치하는 열에 일치한다. 원자 뒤에 정수 ij가 있는 한계가 있으면 원자와 i 번에서 j 번까지 사이로 일치하는 열에 일치한다.

원자(atom)란 "()"로 감싼 정규 표현식이거나 (그 정규 표현식에 일치), 빈 "()" 이거나 (널 문자열에 일치)(!), 대괄호 식이거나 (아래 참고), '.'이거나 (아무 문자 한 개와 일치), '^'이거나 (행 시작의 널 문자열에 일치), '$'이거나 (행 끝의 널 문자열에 일치), '\' 뒤에 "^.[$()|*+?{\" 중 하나가 오는 것이거나 (그 문자 그대로와 일치), '\' 다음에 다른 문자(!)가 오는 것이거나 ('\'가 없는 것처럼 그 문자 그대로와 일치(!)), 다른 특수 의미 없는 문자 하나이다 (그 문자와 일치). '{' 뒤에 오는 게 숫자가 아니면 한계 시작이 아니라 보통 문자다(!). RE 식을 '\'로 끝마치는 건 적법하지 않다.

대괄호 식(bracket expression)이란 "[]"로 감싼 문자 목록이다. 보통은 그 목록의 아무 문자 하나와 일치한다 (단 아래 참고). 목록이 '^'로 시작하면 그 목록 나머지에 없는 아무 문자 하나와 일치한다 (단 아래 참고). 목록 내의 두 문자가 '-'로 연결돼 있는 건 조합열(collating sequence)에서 그 둘 사이 문자들 모두(그 두 문자도 포함)에 해당하는 범위(range)를 나타낸다. 예를 들어 ASCII에서 "[0-9]"는 10진수 숫자와 일치한다. "a-c-e"처럼 두 범위의 겹치는 끝점을 하나로 쓰는 건 적법하지 않다(!). 범위는 조합열에 매우 의존적이며 따라서 이식 가능한 프로그램에서는 사용을 피하는 게 좋다.

목록에 ']' 자체를 포함시키려면 첫 번째 문자이도록 (그 앞에 '^' 가능) 하면 된다. '-' 자체를 포함시키려면 첫 번째나 마지막 문자이도록 하면 되며, 아니면 범위의 뒤쪽 끝점이어도 된다. '-' 자체를 범위의 앞쪽 끝점으로 쓰려면 "[." 및 ".]"로 감싸서 조합 항목(collating element)으로 만들어 주면 된다 (아래 참고). 이 경우들과 '['를 쓰는 몇 가지 조합들(다음 문단 참고)을 제외하면 대괄호 내에선 '\'를 포함한 여타 모든 특수 문자들의 특수 의미가 없어진다.

대괄호 식 내에서 조합 항목(문자, 한 문자인 것처럼 조합되는 다문자 열, 또는 앞의 둘 중 하나를 가리키는 조합열 이름)을 "[." 및 ".]"로 감싼 것은 그 조합 항목의 문자 열을 나타낸다. 그 열은 대괄호 식 목록에서 단일 항목이다. 따라서 다문자 조합 항목을 담은 대괄호 식이 여러 문자에 일치할 수 있다. 예를 들어 조합 열에 "ch"라는 조합 항목이 포함돼 있다면 RE "[[.ch.]]*c"가 "chchcc"의 처음 다섯 문자에 일치한다.

대괄호 식 내에서 "[=" 및 "=]"로 감싼 조합 항목은 동치류(equivalence class)로서 그 항목과 동등한 모든 조합 항목들(그 항목 자체도 포함)의 문자 열들을 나타낸다. (동등한 다른 조합 항목이 없으면 "[." 및 ".]"로 감싼 것처럼 취급한다.) 예를 들어 o와 ^가 같은 동치류에 속하다면 "[[=o=]]", "[[=^=]]", "[o^]"가 모두 같은 걸 뜻한다. 동치류는 범위의 끝점이 될 수 없다(!).

대괄호 식 내에서 "[:" 및 ":]"로 감싼 문자 유형(character class) 이름은 그 유형에 속한 모든 문자들의 목록을 나타낸다. 표준 문자 유형 이름은 다음과 같다.

alnum   digit   punct
alpha   graph   space
black   lower   upper
cntrl   print   xdigit

이는 wctype(3)에 정의돼 있는 문자 유형들이다. 로캘에서 다른 유형들도 제공할 수 있다. 문자 유형은 범위의 끝점으로 쓸 수 없다.

한 RE 식이 어떤 문자열의 여러 부분열에 일치할 수 있는 경우에는 문자열에서 가장 일찍 시작하는 부분열에 일치하게 된다. 그 지점에서 시작하는 여러 부분열에 일치할 수 있으면 가장 긴 것에 일치하게 된다. 하위식 역시도 가장 긴 부분열에 일치하되 전체 일치 길이가 가능한 한 길어야 한다는 제약 내에서이며, RE 내에서 일찍 시작하는 하위식이 이후 하위식보다 높은 우선순위를 가진다. 더 상위의 하위식이 그 부분을 이루는 하위식보다 높은 우선순위를 가진다는 점에 유의하라.

일치 길이는 조합 항목이 아니라 문자 단위로 센다. 널 문자열은 일치하지 않는 것보다는 긴 것으로 본다. 예를 들어 "bb*"는 "abbbc"의 가운데 세 문자에 일치하고, "(wee|week)(knights|nights)"는 "weeknights"의 10개 문자 모두에 일치하며, "(.*).*"를 "abc"에 맞춰 볼 때 괄호 친 하위식이 세 문자 모두에 일치하고, "(a*)*"를 "bc"에 맞춰 볼 때 RE 식 전체와 괄호 친 하위식 모두가 널 문자열에 일치한다.

대소문자 구별 없는 검사를 지정한 경우 그 효과는 알파벳에서 대소문자 구분이 모두 사라진 것과 같다. 구별이 있는 알파벳이 대괄호 식 밖에 보통 문자로 등장할 때는 두 경우 모두를 담은 대괄호 식으로 변환되는 효과가 난다. 예를 들어 'x'는 "[xX]"가 된다. 대괄호 식 안에 등장할 때에는 대응 문자가 그 대괄호 식에 추가된다. 그래서 예를 들어 "[x]"는 "[xX]"가 되고 "[^x]"는 "[^xX]"가 된다.

RE 식 길이에는 특별한 제한이 없다(!). 이식성이 있어야 하는 프로그램에서는 256 바이트를 넘는 RE를 사용하지 않는 게 좋다. 구현체에서 그런 RE를 받아들이지 않아도 POSIX 준수일 수 있다.

구식 ("기본") 정규 표현식은 여러 측면에서 다르다. '|', '+', '?'가 보통 문자이고 그 기능에 대응하는 게 없다. 한계의 구분자가 "\{" 및 "\}"이며 '{'와 '}'는 보통 문자이다. 하위식의 괄호가 "\(" 및 "\)"이며 '('와 ')'는 보통 문자이다. '^'가 RE 시작이나 괄호 친 하위식의 시작(!)에서를 제외하면 보통 문자이고, '$'가 RE 끝이나 괄호 친 하위식 끝(!)에서를 제외하면 보통 문자이며, '*'가 RE 시작이나 괄호 친 하위식의 시작(!)에 (또는 '^' 뒤에) 등장하는 경우 보통 문자이다.

끝으로 역참조(back reference)라는 새로운 종류의 원자가 있다. '\' 뒤에 0 아닌 10진수 숫자 d가 오면 d 번째 괄호 친 하위식(여는 괄호 위치에 따라 왼쪽에서 오른쪽으로 번호 매김)에 일치한 문자 열과 같은 열에 일치한다. 그래서 예를 들어 "\([bc]\)\1"이 "bb"나 "cc"에는 일치하지만 "bc"에는 일치하지 않는다.

BUGS

RE가 두 종류가 있는 점이 구리다.

현행 POSIX.2 명세에서는 짝 없는 '('가 없을 때 ')'가 보통 문자라고 하고 있다. 이는 의도치 않은 문구 실수의 결과였으며 아마 바뀌게 될 것이다. 그 내용에 의지하는 걸 피해야 한다.

역참조는 끔찍하게 구리며 효율적인 구현을 만드는 데 심각한 문제를 야기한다. 게다가 좀 애매하게 정의돼 있다. ("a\(\(b\)*\2\)*d"는 "abbbd"에 일치할까?) 사용을 피해야 한다.

대소문자 구별 없는 검사에 대한 POSIX.2의 명세가 애매하다. 위에 나온 "한쪽이 모든 경우를 나타냄"이라는 정의는 구현자들이 현재 올바른 해석이라고 합의하는 방식이다.

AUTHOR

이 페이지는 Henry Spencer의 regex 패키지에서 가져온 것이다.

SEE ALSO

grep(1), regex(3)

POSIX.2 2.8절 (Regular Expression Notation)


2020-08-13