2005년 11월 04일
CLI :: Regular expressions and Metacharacters
- Regular expression(정규표현식)
- 문자열(string, set of characters)의 패턴(pattern)을 기술하는 표현식(expression)
- Literal characters
가장 기본적인 것으로 하나의 문자로 그 패턴을 표현한다. - Character classes(, Character sets)
지정 가능한 임의의 문자들의 집합이나 특정 범위의 문자들로 부터 오직 하나의 문자를 매치시킨다. [, ]를 사용하며, [ ], [ - ], [^ ]으로 기능이 분류된다.
(Shorthand 표기법) \d, \D, \w, \W, \s, \S와 같이 간편하게 문자의 집합을 지정할 수도 있다. - Alternation(, Union of expressions, OR operation)
하위 표현식(subexpression)을 vertical bar(|)로 구분해 나열한다. 표현식의 합집합으로 각각의 표현식들이 교대로 모두 적용된다. - Repetition(, Quantification)
앞의 표현식이 얼마나 자주 반복될 지를 기술한다. ?, *, +, {, }, *?, +?를 사용하며, {m}, {m, }, { , n}, {m, n}의 형식으로 반복 횟수를 지정할 수 있다. - Anchors
문자가 아닌 위치(position)을 표현하며, ^, $, \b, \B를 사용한다.
zero-width patterns이다. - Grouping
( )를 사용해 표현식의 블럭(재호출 가능한 Marked subexpression)이나 표현식의 실행단위(Atom) 및 적용의 우선순위를 기술한다. - Backreferences
\digit(1-9)의 형식으로 이전에 매치된 블럭(Marked subexpression)를 재호출 및 역참조한다. 정의된 블럭의 순서를 통해 재호출 또는 역참조하며, 전체 표현식 내에 마킹 가능한 블럭의 최대 개수는 1~9개이다.
- Literal characters
- Metacharacter(메타문자)
- 표현식에서 본래의 문자적(literal) 의미가 아닌 특수한 의미로 사용되는 문자
grep, "search globally for matches to the regular expression, and print lines"
sed, stream editor
[root@haan Working]# cat test.txt
he is a rat
he is in a rut
I like root beer
[root@haan Working]# grep 'r.t' test.txt
he is a rat
he is in a rut
he is a rat
he is in a rut
I like root beer
[root@haan Working]# grep 'r.t' test.txt
he is a rat
he is in a rut
- |
- 구분되어 나열된 각각의 패턴을 모두 매치한다. 적용 우선순위가 가장 낮다는 것에 유의해야 하며, 우선순위를 높이기 위해서는 ( )를 사용한다.
[root@haan Working]# cat test.txt
The pet store sold cats, dogs, and birds.
# 확장 표현식을 위해 grep의 -E 옵션, 또는 egrep를 사용한다.
[root@haan Working]# grep -E 'cat|dog|bird' test.txt
The pet store sold cats, dogs, and birds.
# 우선 순위가 가장 낮고, ()를 사용해 우선순위를 높일 수 있다.
[root@haan Working]# grep -E 'cat|dog.|bird' test.txt
The pet store sold cats, dogs, and birds.
[root@haan Working]# grep -E '(cat|dog).|bird' test.txt
The pet store sold cats, dogs, and birds.
The pet store sold cats, dogs, and birds.
# 확장 표현식을 위해 grep의 -E 옵션, 또는 egrep를 사용한다.
[root@haan Working]# grep -E 'cat|dog|bird' test.txt
The pet store sold cats, dogs, and birds.
# 우선 순위가 가장 낮고, ()를 사용해 우선순위를 높일 수 있다.
[root@haan Working]# grep -E 'cat|dog.|bird' test.txt
The pet store sold cats, dogs, and birds.
[root@haan Working]# grep -E '(cat|dog).|bird' test.txt
The pet store sold cats, dogs, and birds.
# grep의 -o 옵션으로 라인을 출력하는 대신 매치되는 부분만을 출력한다.
[root@haan ~]# grep -o 'gr[ae]y'
it matches both gray or grey.
gray
grey
# sed는 패턴 검색 후 새 문자열로 대체한다. 's/패턴/새문자열/g'의 형식이다.
# 벗겨달란다. 기꺼이 HTML 태그를 벗겨내 본다.
[root@haan ~]# sed 's/<[^>]*>//g'
<strong>strip me</strong>
strip me
[root@haan ~]# grep -o 'gr[ae]y'
it matches both gray or grey.
gray
grey
# sed는 패턴 검색 후 새 문자열로 대체한다. 's/패턴/새문자열/g'의 형식이다.
# 벗겨달란다. 기꺼이 HTML 태그를 벗겨내 본다.
[root@haan ~]# sed 's/<[^>]*>//g'
<strong>strip me</strong>
strip me
- \d
- numeric character, [0-9_]와 같은 의미이다.
- \D
- non-numeric character, [^0-9_] 또는 [^\d]와 같은 의미이다.
- \w
- word character, 일반적으로 [A-Za-z0-9_]와 같은 의미이다.
- \W
- non-word character, 일반적으로 [^A-Za-z0-9_] 또는 [^\w]와 같은 의미이다.
- \s
- whitespace character, [ \t]와 같은 의미이다.
- \S
- non-whitespace character, [^ \t] 또는 [^\s]와 같은 의미이다.
# 위의 표기법은 grep, sed에서 지원하지 않는다. python을 사용하자.
# [\S\D]와 [^\s\d]는 다르다는 것에 유의하자.
[root@haan Working]# python
>>> import re
>>> text = "x 8"
>>> print re.sub("[\S\D]", "r", text)
rrr
>>> print re.sub("[^\s\d]", "r", text)
r 8
>>> Ctrl-D
# [\S\D]와 [^\s\d]는 다르다는 것에 유의하자.
[root@haan Working]# python
>>> import re
>>> text = "x 8"
>>> print re.sub("[\S\D]", "r", text)
rrr
>>> print re.sub("[^\s\d]", "r", text)
r 8
>>> Ctrl-D
- ^
- Multi-line mode에서 라인의 시작 위치와 매치된다.
- $
- Multi-line mode에서 라인의 끝 위치와 매치된다.
- \b
- (word boundary) matches before and after an alphanumeric sequence, non-word charater(\W)로 둘러싸인 word character(\w)의 전/후 위치가 매치된다.
\B is the negated version of \b.
[root@haan Working]# cat test.txt
line, at the first
This is the second line
# 실행 후 실제 출력 부분은 노란색으로 구분하였다.
[root@haan Working]# grep '^line' test.txt
line, at the first
[root@haan Working]# grep 'line$' test.txt
This is the second line
# "c"로 시작해서 "t"로 끝나는 단어("cat")를 추출해 보자.
[root@haan ~]# grep -o '\bc.*t\b'
um... can you match cat only?
can you match cat
# 헤헤... 예상대로 실패다.
# 스페이스를 제외([^ ])하고 다시 한다.
[root@haan ~]# grep -o '\bc[^ ]*t\b'
um... can you match cat only?
cat
# 성공이다!!
line, at the first
This is the second line
# 실행 후 실제 출력 부분은 노란색으로 구분하였다.
[root@haan Working]# grep '^line' test.txt
line, at the first
[root@haan Working]# grep 'line$' test.txt
This is the second line
# "c"로 시작해서 "t"로 끝나는 단어("cat")를 추출해 보자.
[root@haan ~]# grep -o '\bc.*t\b'
um... can you match cat only?
can you match cat
# 헤헤... 예상대로 실패다.
# 스페이스를 제외([^ ])하고 다시 한다.
[root@haan ~]# grep -o '\bc[^ ]*t\b'
um... can you match cat only?
cat
# 성공이다!!
[root@haan ~]# grep -E -o 'colou?r'
how spell the word, "color" or "colour"?
color
colour
# 메타문자를 원래의 literal 의미로 쓰고자 할 때는 백슬래시()로 escape시킨다.
# 확장 표현식을 위해 sed의 -r 옵션을 사용한다.
[root@haan ~]# sed -r s/'Jan.?(uary)?'/01/g
Jan or Jan. or January
01 or 01 or 01
10-Jan-2005, 20-Jan.-2005, 30-January-2005
10-01-2005, 20-01-2005, 30-01-2005
how spell the word, "color" or "colour"?
color
colour
# 메타문자를 원래의 literal 의미로 쓰고자 할 때는 백슬래시()로 escape시킨다.
# 확장 표현식을 위해 sed의 -r 옵션을 사용한다.
[root@haan ~]# sed -r s/'Jan.?(uary)?'/01/g
Jan or Jan. or January
01 or 01 or 01
10-Jan-2005, 20-Jan.-2005, 30-January-2005
10-01-2005, 20-01-2005, 30-01-2005
- *
- 바로 전의 표현식(block)을 0, 1 or any number 횟수만큼 반복한다.
- +
- 바로 전의 표현식(block)을 at least(>=) 1, 즉 최소한 한번 이상 반복한다.
[root@haan ~]# grep -o 'go*gle'
how often? zero time, ggle
ggle
how often? one time, gogle
gogle
how often? more times, gooooooogle
gooooooogle
# 위와는 달리 "ggle"은 매치되지 않음을 알 수 있다.
[root@haan ~]# grep -E -o 'go+gle'
how often? zero time, ggle
how often? one time, gogle
gogle
how often? more times, gooooooogle
gooooooogle
how often? zero time, ggle
ggle
how often? one time, gogle
gogle
how often? more times, gooooooogle
gooooooogle
# 위와는 달리 "ggle"은 매치되지 않음을 알 수 있다.
[root@haan ~]# grep -E -o 'go+gle'
how often? zero time, ggle
how often? one time, gogle
gogle
how often? more times, gooooooogle
gooooooogle
- Lazy(Non-greedy) quantifiers
- 반복연산자 *, +는 기본적으로 breedy해서 가능한 최대로 매치하는데, 매치를 최소로 제한하기 위해서 Lazy quatifiers(*?, +?)를 사용한다.
# Greedy, as much as possible
[root@haan Working]# grep -P -o 'L.*s '
Lazy quantifier grab as little as possible.
Lazy quantifier grab as little as
# Lazy, as little as possible
[root@haan Working]# grep -P -o 'L.*?s '
Lazy quantifier grab as little as possible.
Lazy quantifier grab as
[root@haan Working]# grep -P -o 'L.*s '
Lazy quantifier grab as little as possible.
Lazy quantifier grab as little as
# Lazy, as little as possible
[root@haan Working]# grep -P -o 'L.*?s '
Lazy quantifier grab as little as possible.
Lazy quantifier grab as
[root@haan Working]# cat test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
# grep가 { ,n}을 지원하지 않아서 {0, n}을 대신 사용한다.
# 실제로 출력되는 부분은 노란색으로 구분하였다.
[root@haan Working]# grep -E -o 'a{5} b{0,6} c{3,4}' test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
[root@haan Working]# grep -E -o 'a+ b{4,} c?' test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
[root@haan Working]# grep -E -o 'a{5} b{6,} c{4,8}' test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
# grep가 { ,n}을 지원하지 않아서 {0, n}을 대신 사용한다.
# 실제로 출력되는 부분은 노란색으로 구분하였다.
[root@haan Working]# grep -E -o 'a{5} b{0,6} c{3,4}' test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
[root@haan Working]# grep -E -o 'a+ b{4,} c?' test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
[root@haan Working]# grep -E -o 'a{5} b{6,} c{4,8}' test.txt
aaaaa bbbbb ccccc
aaa bbb ccc
aaaaa bbbbbbbbbbbbbb ccccc
- ( )
- 표현식의 실행단위(Atom) 및 적용의 우선순위를 지정하기 위한 Grouping에 사용되며, 동시에 Backreference(역참조 or 재호출)을 위한 Marked subexpression을 정의한다.
[root@haan Working]# cat test.txt
Billy tried really hard.
Sally tried really really hard.
Timmy tried really really really hard.
# "really "가 1번 이상 반복되는 문자열을 "very " 문자열로 바꿔보자.
# 'really ' 표현식을 ()로 grouping한 후 1번 이상(+) 반복 매치한다.
[root@haan Working]# sed -r 's/(really )+/very /g' test.txt
Billy tried very hard.
Sally tried very hard.
Timmy tried very hard.
[root@haan Working]# cat test.txt
abc xyz
xyz abc
abc abc
xyz xyz
# '(abc|xyz)' marked block을 정의하고 '\1'을 통해 그 것을 재호출한다.
[root@haan Working]# egrep '(abc|xyz) \1' test.txt
abc xyz
xyz abc
abc abc
xyz xyz
# 다음 예제를 보면 단순 반복과 재호출의 차이점을 알 수 있다.
[root@haan Working]# egrep '(abc|xyz) (abc|xyz)' test.txt
abc xyz
xyz abc
abc abc
xyz xyz
Billy tried really hard.
Sally tried really really hard.
Timmy tried really really really hard.
# "really "가 1번 이상 반복되는 문자열을 "very " 문자열로 바꿔보자.
# 'really ' 표현식을 ()로 grouping한 후 1번 이상(+) 반복 매치한다.
[root@haan Working]# sed -r 's/(really )+/very /g' test.txt
Billy tried very hard.
Sally tried very hard.
Timmy tried very hard.
[root@haan Working]# cat test.txt
abc xyz
xyz abc
abc abc
xyz xyz
# '(abc|xyz)' marked block을 정의하고 '\1'을 통해 그 것을 재호출한다.
[root@haan Working]# egrep '(abc|xyz) \1' test.txt
abc xyz
xyz abc
abc abc
xyz xyz
# 다음 예제를 보면 단순 반복과 재호출의 차이점을 알 수 있다.
[root@haan Working]# egrep '(abc|xyz) (abc|xyz)' test.txt
abc xyz
xyz abc
abc abc
xyz xyz
[root@haan Working]# cat test.txt
foo(x+13,y-2);
foo(bar(8),x+y+z);
# 매개변수가 2개인 함수의 매개변수들의 위치를 서로 바꿔보자.
[root@haan Working]# sed -r
> 's/([A-Za-z0-9_]+)(([^,]*),([^,]*))/\1(\3,\2)/g'
> test.txt
foo(y-2,x+13);
foo(x+y+z,bar(8));
# 아래 예제도 잘 살표보자.
[root@haan Working]# sed -r 's/([A-Z])([0-9]{2,4}) /\2:\1 /g'
A37 B4 C107 D54112 E1103 XXX
37:A B4 107:C D54112 1103:E XXX
# '(?:pattern)'과 같이 하면 marking하지 않고 grouping이 가능하다.
# grep와 sed 등은 지원하지 않는 표기법이다.
[root@haan Working]# python
>>> import re
>>> text = "A-xyz-37 # B:abcd:142 # C-wxy-66 # D-qrs-93"
>>> print re.sub("([A-Z])(?:-[a-z]{3}-)([0-9]*)", "\1\2", text)
A37 # B:abcd:142 # C66 # D93
>>> Ctrl-D
foo(x+13,y-2);
foo(bar(8),x+y+z);
# 매개변수가 2개인 함수의 매개변수들의 위치를 서로 바꿔보자.
[root@haan Working]# sed -r
> 's/([A-Za-z0-9_]+)(([^,]*),([^,]*))/\1(\3,\2)/g'
> test.txt
foo(y-2,x+13);
foo(x+y+z,bar(8));
# 아래 예제도 잘 살표보자.
[root@haan Working]# sed -r 's/([A-Z])([0-9]{2,4}) /\2:\1 /g'
A37 B4 C107 D54112 E1103 XXX
37:A B4 107:C D54112 1103:E XXX
# '(?:pattern)'과 같이 하면 marking하지 않고 grouping이 가능하다.
# grep와 sed 등은 지원하지 않는 표기법이다.
[root@haan Working]# python
>>> import re
>>> text = "A-xyz-37 # B:abcd:142 # C-wxy-66 # D-qrs-93"
>>> print re.sub("([A-Z])(?:-[a-z]{3}-)([0-9]*)", "\1\2", text)
A37 # B:abcd:142 # C66 # D93
>>> Ctrl-D
- Lookahead assertions
- (?=pattern) for positive assertions, and (?!pattern) for negative assertions.
They are not backreferenced and not marked, likewise (?:pattern).
[root@haan Working]# python
>>> import re
>>> text = "A-xyz37 # B-ab6142 # C-Wxy66 # D-qrs93"
>>> print re.sub("([A-Z])-(?=[a-z]{3})([^\s#]*)", "\2-\1", text)
xyz37-A # B-ab6142 # C-Wxy66 # qrs93-D
>>> print re.sub("([A-Z])-(?![a-z]{3})([^\s#]*)", "\2-\1", text)
A-xyz37 # ab6142-B # Wxy66-C # D-qrs93
>>> Ctrl-D
[root@haan ~]# python
>>> import re
>>> txt = "Iraq is a country, but not Eraq"
>>> print re.sub("([^ ]*)q[^u]", "\1k", txt)
Irakis a country, but not Eraq
>>> print re.sub("([^ ]*)q(?!u)", "\1k", txt)
Irak is a country, but not Erak
>>> Ctrl-D
>>> import re
>>> text = "A-xyz37 # B-ab6142 # C-Wxy66 # D-qrs93"
>>> print re.sub("([A-Z])-(?=[a-z]{3})([^\s#]*)", "\2-\1", text)
xyz37-A # B-ab6142 # C-Wxy66 # qrs93-D
>>> print re.sub("([A-Z])-(?![a-z]{3})([^\s#]*)", "\2-\1", text)
A-xyz37 # ab6142-B # Wxy66-C # D-qrs93
>>> Ctrl-D
[root@haan ~]# python
>>> import re
>>> txt = "Iraq is a country, but not Eraq"
>>> print re.sub("([^ ]*)q[^u]", "\1k", txt)
Irakis a country, but not Eraq
>>> print re.sub("([^ ]*)q(?!u)", "\1k", txt)
Irak is a country, but not Erak
>>> Ctrl-D
- Basic and Extended Specifications Issue 6
- Regular-Expressions.info - Tutorial, Examples and Reference
- A Tao of Regular Expressions
- Regular expressions with Perl examples by Wikipedia
- Regexp Syntax Summary
- Learning to Use Regular Expressions
