일러두기

이 문서에서는 PCRE 실제 사례 예제를 위해 다음을 사용한다.

  • [[/cmd/grep]]{GNU grep}의 -P 옵션
  • [[/database/sqlite]]의 REGEXP

SQLite의 REGEXP는 다른 DB에서는 다른 문법으로 지원한다.

예를 들어 MariaDB에서는 RLIKE를 사용한다.

man

man 3 pcresyntax

QUOTING

\Q...\E \Q\E 사이의 문자열을 메타문자로 해석하지 않음

특수문자가 많이 포함된 문자열을 검색하고자 할 때 유용하다.

[[/cmd/grep]]{GNU grep}에서 -P 옵션으로 사용할 수 있다. (BSD grep에서는 지원하지 않음)

 # 대괄호를 이스케이핑하지 않아도 되므로 편리하다
grep -P '\Q[[/cmd]]\E' -R
select '[[/cmd]]' REGEXP '\Q[[/cmd]]\E';

CHARACTERS

\a BEL 문자 (hex 07)
\cx "control-x", x 는 ASCII 문자
\e escape (hex 1B)
\f form feed (hex 0C)
\n newline (hex 0A)
\r carriage return (hex 0D)
\t tab (hex 09)
\0dd 8진수 표기 문자
\ddd 8진수 표기 문자 또는 백 레퍼런스
\o{ddd..} 8진수 표기 문자
\xhh 16진수 표기 문자
\x{hhh..} 16진수 표기 문자
echo 'a' | ggrep -Po '\x{61}'
select 'a' REGEXP '\x{61}';

CHARACTER TYPES

. newline을 제외한 모든 문자. dotall mode 에서는 모든 문자.
\C one data unit, even in UTF mode (best avoided). (바이트 1개이므로 주의)
\d 십진수 숫자. [0-9].
\D \d의 반대
\h 수평 공백 문자. [ \t].
\H \h의 반대
\N 개행문자가 아닌 문자. [^\r\n]
\R a newline sequence. \r\n, \n, \r 등 플랫폼 상관없이 줄바꿈 문자열.
\s 모든 공백 문자. [ \t\r\n\v\f].
\S \s의 반대
\v 수직 탭 문자. \v
\V \v의 반대
\w a "word" character. [a-zA-Z0-9_]
\W \w의 반대
\X a Unicode extended grapheme cluster
\p{xx} category property 문자 (다음 섹션 참고)
\P{xx} \p{xx}의 반대

GENERAL CATEGORY PROPERTIES

\p\P에서 사용한다.

C Other  
Cc Control  
Cf Format  
Cn Unassigned  
Co Private use  
Cs Surrogate  
L& Ll, Lu, or Lt  
L Letter  
Ll Lower case letter [a-z]
Lm Modifier letter  
Lo Other letter  
Lt Title case letter  
Lu Upper case letter [A-Z]
M Mark  
Mc Spacing mark  
Me Enclosing mark  
Mn Non-spacing mark  
Nd Decimal number [0-9]
Nl Letter number  
No Other number  
P Punctuation . ! ? ;
Pc Connector punctuation  
Pd Dash punctuation  
Pf Final punctuation  
Pi Initial punctuation  
Po Other punctuation  
S Symbol  
Sk Modifier symbol  
So Other symbol  
Z Separator  
Zl Line separator  
Zp Paragraph separator  
Zs Space separator  
Sm Mathematical symbol + = < > 등 수학 기호 (키보드의 - 제외)
-- sqlite
select '×±+−÷√∑∫∴¬∵~=≠≈≅⇔↔<>∀∃∪∩' REGEXP '\p{Sm}+';
--> 1
Sc Currency symbol $ £ 등 모든 화폐 기호
-- sqlite
select '$₩£€¥₽₹' REGEXP '\p{Sc}+';
--> 1
N Number 1 ¼ 등 모든 숫자 기호
-- sqlite
SELECT '1¼①' REGEXP '^\p{N}+$';
--> 1
Ps Open punctuation ( [ { 등 여는 괄호 (<는 제외)
Pe Close punctuation ) ] } 등 닫는 괄호 (>는 제외)
-- sqlite
select '([{' REGEXP '\p{Ps}+';
--> 1

select '[a' REGEXP '\p{Ps}a';
--> 1

PCRE SPECIAL CATEGORY PROPERTIES

\p\P에서 사용한다.

Xan Alphanumeric: union of properties L and N
Xps POSIX space: property Z or tab, NL, VT, FF, CR
Xsp Perl space: property Z or tab, NL, VT, FF, CR
Xuc Universally-named character: one that can be represented by a Universal Character Name
Xwd Perl word: property Xan or underscore

SCRIPT NAMES

국가/언어별 문자셋으로, \p\P에서 사용한다.

다음 언어들을 지원한다.

Arabic, Armenian, Avestan, Balinese, Bamum, Bassa_Vah, Batak, Bengali, Bopomofo, Brahmi, Braille, Buginese, Buhid, Canadian_Aboriginal, Carian, Caucasian_Albanian, Chakma, Cham, Cherokee, Common, Coptic, Cuneiform, Cypriot, Cyrillic, Deseret, Devanagari, Duployan, Egyptian_Hieroglyphs, Elbasan, Ethiopic, Georgian, Glagolitic, Gothic, Grantha, Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, Imperial_Aramaic, Inherited, Inscriptional_Pahlavi, Inscriptional_Parthian, Javanese, Kaithi, Kannada, Katakana, Kayah_Li, Kharoshthi, Khmer, Khojki, Khudawadi, Lao, Latin, Lepcha, Limbu, Linear_A, Linear_B, Lisu, Lycian, Lydian, Mahajani, Malayalam, Mandaic, Manichaean, Meetei_Mayek, Mende_Kikakui, Meroitic_Cursive, Meroitic_Hieroglyphs, Miao, Modi, Mongolian, Mro, Myanmar, Nabataean, New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_North_Arabian, Old_Permic, Old_Persian, Old_South_Arabian, Old_Turkic, Oriya, Osmanya, Pahawh_Hmong, Palmyrene, Pau_Cin_Hau, Phags_Pa, Phoenician, Psalter_Pahlavi, Rejang, Runic, Samaritan, Saurashtra, Sharada, Shavian, Siddham, Sinhala, Sora_Sompeng, Sundanese, Syloti_Nagri, Syriac, Tagalog, Tagbanwa, Tai_Le, Tai_Tham, Tai_Viet, Takri, Tamil, Telugu, Thaana, Thai, Tibetan, Tifinagh, Tirhuta, Ugaritic, Vai, Warang_Citi, Yi.

$ echo 'ΣΦΩ' | ggrep -P '^\p{Greek}+$';
ΣΦΩ

$ echo '가나다' | ggrep -P '^\p{Hangul}+$';
가나다

$ echo '語' | ggrep -P '^\p{Han}+$';$ echo 'ア' | ggrep -P '^\p{Katakana}+$';$ echo 'あお' | ggrep -P '^\p{Hiragana}+$';
あお
  • script names는 sqlite에서는 지원하지 않는다.

CHARACTER CLASSES

[...] positive character class
[^...] negative character class
[x-y] range (can be used for hex characters)
\[[:xxx:]] positive POSIX named set
\[[:^xxx:]] negative POSIX named set

POSIX NAMED SETS

POSIX named set은 다음과 같다.

alnum alphanumeric
alpha alphabetic
ascii 0-127
blank space or tab
cntrl control character
digit decimal digit
graph printing, excluding space
lower lower case letter
print printing, including space
punct printing, excluding alphanumeric
space white space
upper upper case letter
word same as \w
xdigit hexadecimal digit

QUANTIFIERS

수량자.

? 0 ~ 1, greedy
?+ 0 ~ 1, possessive
?? 0 ~ 1, lazy
* 0 이상, greedy
*+ 0 이상, possessive
*? 0 이상, lazy
+ 1 이상, greedy
++ 1 이상, possessive
+? 1 이상, lazy
{n} n 번
{n,m} n ~ m, greedy
{n,m}+ n ~ m, possessive
{n,m}? n ~ m, lazy
{n,} n 이상, greedy
{n,}+ n 이상, possessive
{n,}? n 이상, lazy

Greedy

  • greedy는 가능한 한 많이 매칭한다.
  • ? * +를 그대로 쓰면 greedy이다.
$ # greedy
$ echo abcabcabc | ggrep -P 'a.*c'
abcabcabc

Possessive

  • possessive는 가능한 한 많이 매칭하되, backtracking을 하지 않는다.
  • ?+ *+ ++처럼 뒤에 +를 붙이면 possessive이다.

possessive는 이해하기 꽤 어려울 수 있다.

$ # possessive
$ echo XXXXZ | ggrep -P 'X++[A-Z]+'
XXXXZ
  • 매치 성공!
    • XXXXX++와 모두 매치시키고 나서,
    • 마지막 Z[A-Z]+와 매치 성공.
$ # possessive
$ echo XXXXX | ggrep -P 'X++[A-Z]+'

  • 매치 실패
    • XXXXXX++와 모두 매치시키고 나서,
    • [A-Z]+를 매치시킬 문자가 남아있지 않음.

백트래킹이 되는 greedy와 비교해보자.

$ # greedy
$ echo XXXXX | ggrep -P 'X+[A-Z]+'
XXXXX
  • 매치 성공!
    • XXXXXX+와 모두 매치시키고 나서,
    • 마지막 [A-Z]+ 와 매치시키기 위해 백트랙(한 글자 왼쪽으로 돌아감),
    • 마지막 X[A-Z]+와 매치 성공.

grep의 오작동

GNU grep을 쓰면 다음과 같은 케이스에서 오작동한다.

$ echo YYXXratsXX | ggrep -Po '([XY]++)rats\1'
XXratsXX

[XY]++YYXX와 매치되기 때문에 \1XXYY가 있어야 전체가 매치되는데, 결과를 보면 XXratsXX가 매치되어 있다.

Lazy

  • lazy는 가능한 한 적게 매칭한다.
    • ?? *? +? ??처럼 뒤에 ?를 붙이면 lazy이다.
$ echo "abcabc" | ggrep -Po '^a.*?c'
abc
  • 왼쪽의 abc가 매치되고, 오른쪽의 abc는 매치되지 않았다.

ANCHORS AND SIMPLE ASSERTIONS

\b word 경계
\B \b와 반대
^ 문자열의 시작지점. multiline 모드에서는 각 행의 시작.
\A 문자열의 (절대적) 시작지점.
$ 문자열의 종료지점. multiline 모드에서는 각 행의 마지막.
\Z 문자열의 (절대적) 종료지점. 또는 절대적 종료지점 개행문자 바로 앞.
\z 문자열의 (절대적) 종료지점.
\G first matching position in subject

MATCH POINT RESET

\K reset start of match

\K 는 positive assertion에서는 작동하지만, negative assertion에서는 무시된다.

ALTERNATION

expr|expr|expr...

|를 사용해 구분한다.

CAPTURING

(...) capturing group
(?<name>...) named capturing group (Perl)
(?'name'...) named capturing group (Perl)
(?P<name>...) named capturing group (Python)
(?:...) non-capturing group
(?|...) non-capturing group; reset group numbers for capturing groups in each alternative

ATOMIC GROUPS

(?>...) atomic, non-capturing group

COMMENT

(?#....) comment (not nestable)

TODO: OPTION SETTING

TODO: NEWLINE CONVENTION

TODO: WHAT \R MATCHES

LOOKAHEAD AND LOOKBEHIND ASSERTIONS

(?=...) positive look ahead
(?!...) negative look ahead
(?<=...) positive look behind
(?<!...) negative look behind

주의: 각각의 look behind의 최상위 branch는 고정된 길이여야 한다.

BACKREFERENCES

\n reference by number (can be ambiguous)
\gn reference by number
\g{n} reference by number
\g{-n} relative reference by number
\k<name> reference by name (Perl)
\k'name' reference by name (Perl)
\g{name} reference by name (Perl)
\k{name} reference by name (.NET)
(?P=name) reference by name (Python)

TODO: SUBROUTINE REFERENCES (POSSIBLY RECURSIVE)

TODO: CONDITIONAL PATTERNS

TODO: BACKTRACKING CONTROL

TODO: CALLOUTS

참고문헌