Perl 정규표현식 빠른 시작
Perl 정규표현식 빠른 시작 (perlrequick)
Perl에서 정규표현식('regexes')을 이해하고, 만들고, 사용하는 아주 기본기를 다루는 페이지예요.
본문
가이드 (The Guide)
이 페이지는 여러분이 "패턴(pattern)"이 어떤 건지, 그리고 패턴을 쓰는 기본 문법을 이미 안다고 가정해요. 아니라면 perlretut을 먼저 보세요.
단순 단어 매치 (Simple word matching)
가장 단순한 정규식은 그냥 단어 하나, 더 일반적으로는 문자 문자열이에요. 단어로 이루어진 정규식은 그 단어를 포함한 어떤 문자열이든 매치해요:
"Hello World" =~ /World/; # matches
이 문장에서 World가 정규식이고, /World/를 감싼 //는 Perl에게 문자열에서 매치를 검색하라고 알려줘요. 연산자 =~는 문자열을 정규식 매치에 연결하고, 정규식이 매치되면 참 값을, 매치되지 않으면 거짓 값을 돌려줘요. 여기서 World는 "Hello World"의 두 번째 단어와 매치되므로 이 표현식은 참이 돼요. 이 아이디어에는 여러 변형이 있어요.
이런 표현식은 조건문에서 유용해요:
print "It matches\n" if "Hello World" =~ /World/;
!~ 연산자를 쓰면 매치의 의미를 뒤집을 수 있어요:
print "It doesn't match\n" if "Hello World" !~ /World/;
정규식 안의 리터럴 문자열은 변수로 대체할 수 있어요:
$greeting = "World";
print "It matches\n" if "Hello World" =~ /$greeting/;
$_ 대상으로 매치한다면 $_ =~ 부분은 생략할 수 있어요:
$_ = "Hello World";
print "It matches\n" if /World/;
마지막으로, 매치의 기본 구분자 //는 앞에 'm'을 붙이면 임의의 구분자로 바꿀 수 있어요:
"Hello World" =~ m!World!; # matches, delimited by '!'
"Hello World" =~ m{World}; # matches, note the matching '{}'
"/usr/bin/perl" =~ m"/perl"; # matches after '/usr/bin',
# '/' becomes an ordinary char
정규식이 문장을 참으로 만들려면 문자열의 일부와 정확히 매치해야 해요:
"Hello World" =~ /world/; # doesn't match, case sensitive
"Hello World" =~ /o W/; # matches, ' ' is an ordinary char
"Hello World" =~ /World /; # doesn't match, no ' ' at end
Perl은 항상 문자열에서 가장 이른 가능한 지점에서 매치해요:
"Hello World" =~ /o/; # matches 'o' in 'Hello'
"That hat is red" =~ /hat/; # matches 'hat' in 'That'
모든 문자가 매치에 "그대로" 쓰일 수 있는 건 아니에요. 메타문자(metacharacters) 라고 불리는 일부 문자는 특별하게 취급되고, 정규식 표기법에 쓰도록 예약돼 있어요. 메타문자는 다음과 같아요.
{}[]()^$.|*+?\
메타문자는 그 앞에 백슬래시를 붙이면 리터럴로 매치할 수 있어요:
"2+2=4" =~ /2+2/; # doesn't match, + is a metacharacter
"2+2=4" =~ /2\+2/; # matches, \+ is treated like an ordinary +
'C:\WIN32' =~ /C:\\WIN/; # matches
"/usr/bin/perl" =~ /\/usr\/bin\/perl/; # matches
마지막 정규식에서 슬래시 '/'도 백슬래시 처리됐어요. 정규식을 구분하는 문자기 때문이죠.
대부분의 메타문자는 항상 특별한 건 아니고, 다른 문자(패턴을 구분하는 문자 같은)는 다양한 상황에서 특별해져요. 이것은 혼란스럽고 예상치 못한 결과를 만들 수 있어요. use re 'strict'가 잠재적 함정을 알려줄 수 있어요.
인쇄 불가능한 ASCII 문자는 이스케이프 시퀀스로 나타내요. 흔한 예로 탭에 \t, 새 줄에 \n, 캐리지 리턴에 \r이 있어요. 임의의 바이트는 8진 이스케이프 시퀀스(예: \033)나 16진 이스케이프 시퀀스(예: \x1B)로 나타내요:
"1000\t2000" =~ m(0\t2) # matches
"cat" =~ /\143\x61\x74/ # matches in ASCII, but
# a weird way to spell cat
정규식은 대부분 이중 인용 문자열처럼 취급되므로, 변수 치환이 동작해요:
$foo = 'house';
'cathouse' =~ /cat$foo/; # matches
'housecat' =~ /${foo}cat/; # matches
위의 모든 정규식에서, 정규식이 문자열의 어디에든 매치되면 매치로 간주했어요. 어디서 매치할지를 지정하려면 앵커 메타문자 ^와 $를 쓰면 돼요. 앵커 ^는 문자열의 시작에서, $는 문자열의 끝(또는 끝의 새 줄 앞)에서 매치하라는 뜻이에요. 몇 가지 예를 볼게요:
"housekeeper" =~ /keeper/; # matches
"housekeeper" =~ /^keeper/; # doesn't match
"housekeeper" =~ /keeper$/; # matches
"housekeeper\n" =~ /keeper$/; # matches
"housekeeper" =~ /^housekeeper$/; # matches
문자 클래스 사용하기 (Using character classes)
문자 클래스(character class) 는 단일 문자 대신 가능한 문자들의 집합이 정규식의 특정 지점에서 매치되게 해 줘요. 문자 클래스에는 여러 종류가 있는데, 사람들이 이 용어를 쓸 때는 보통 이 섹션에서 설명하는 종류, 기술적으로 "브래킷 문자 클래스(Bracketed character classes)"라고 불리는 걸 가리켜요. 문자가 매치될 수 있는 집합을 안에 담은 대괄호 [...]로 표기하기 때문이죠. 아래에서는 흔한 용법에 맞춰 "bracketed"를 생략할게요. (브래킷) 문자 클래스의 몇 가지 예를 볼게요:
/cat/; # matches 'cat'
/[bcr]at/; # matches 'bat', 'cat', or 'rat'
"abc" =~ /[cab]/; # matches 'a'
마지막 문장에서, 'c'가 클래스의 첫 번째 문자지만 정규식이 매치할 수 있는 가장 이른 지점은 'a'예요.
/[yY][eE][sS]/; # match 'yes' in a case-insensitive way
# 'yes', 'Yes', 'YES', etc.
/yes/i; # also match 'yes' in a case-insensitive way
마지막 예시는 'i' 수정자가 붙은 매치를 보여줘요. 이 수정자는 매치를 대소문자 구분 없이 만들어요.
문자 클래스도 보통 문자와 특수 문자가 있지만, 클래스 안의 보통·특수 문자 집합은 클래스 밖과 달라요. 문자 클래스의 특수 문자는 -]\^$이고 이스케이프로 매치해요:
/[\ ]c]def/; # matches ']def' or 'cdef'
$x = 'bcr';
/[$x]at/; # matches 'bat, 'cat', or 'rat'
/[\$x]at/; # matches '$at' or 'xat'
/[\\$x]at/; # matches '\at', 'bat, 'cat', or 'rat'
특수 문자 '-'는 문자 클래스 안에서 범위 연산자로 동작해요. 그래서 다루기 힘든 [0123456789]와 [abc...xyz]가 날씬한 [0-9]와 [a-z]가 돼요:
/item[0-9]/; # matches 'item0' or ... or 'item9'
/[0-9a-fA-F]/; # matches a hexadecimal digit
'-'가 문자 클래스의 첫 번째나 마지막 문자라면 보통 문자로 취급돼요.
특수 문자 ^가 문자 클래스의 첫 번째 위치에 오면 부정 문자 클래스(negated character class) 를 나타내요. 대괄호 안의 문자를 제외한 어떤 문자든 매치하죠. [...]와 [^...] 모두 반드시 한 문자를 매치해야 하고, 그렇지 않으면 매치가 실패해요. 그래서:
/[^a]at/; # doesn't match 'aat' or 'at', but matches
# all other 'bat', 'cat, '0at', '%at', etc.
/[^0-9]/; # matches a non-numeric character
/[a^]at/; # matches 'aat' or '^at'; here '^' is ordinary
Perl은 흔한 문자 클래스에 대한 여러 약어를 갖고 있어요. (이 정의들은 Perl이 /a 수정자와 함께 ASCII-안전 모드에서 쓰는 것입니다. 그렇지 않으면 훨씬 더 많은 비-ASCII Unicode 문자도 매치할 수 있어요. 자세한 내용은 "Backslash sequences" in perlrecharclass를 보세요.)
\d는 숫자(digit)이고 다음을 나타내요.
[0-9]
\s는 공백 문자(whitespace)이고 다음을 나타내요.
[\ \t\r\n\f]
\w는 단어 문자(영숫자 또는 _)이고 다음을 나타내요.
[0-9a-zA-Z_]
\D는 부정\d예요. 숫자를 제외한 어떤 문자든 나타내요.
[^0-9]
\S는 부정\s예요. 어떤 비-공백 문자든 나타내요.
[^\s]
\W는 부정\w예요. 어떤 비-단어 문자든 나타내요.
[^\w]
- 마침표
'.'는"\n"을 제외한 어떤 문자와도 매치해요.
\d\s\w\D\S\W 약어는 문자 클래스 안팎 모두에서 쓸 수 있어요. 사용 예시를 볼게요:
/\d\d:\d\d:\d\d/; # matches a hh:mm:ss time format
/[\d\s]/; # matches any digit or whitespace character
/\w\W\w/; # matches a word char, followed by a
# non-word char, followed by a word char
/..rt/; # matches any two chars, followed by 'rt'
/end\./; # matches 'end.'
/end[.]/; # same thing, matches 'end.'
단어 앵커 \b는 단어 문자와 비-단어 문자 사이의 경계 \w\W 또는 \W\w와 매치해요:
$x = "Housecat catenates house and cat";
$x =~ /\bcat/; # matches cat in 'catenates'
$x =~ /cat\b/; # matches cat in 'housecat'
$x =~ /\bcat\b/; # matches 'cat' at end of string
마지막 예시에서 문자열의 끝은 단어 경계로 간주돼요.
자연어 처리용으로(예를 들어 아포스트로피를 단어에 포함시키려면) 대신 \b{wb}를 써요.
"don't" =~ / .+? \b{wb} /x; # matches the whole string
이것 아니면 저것 매치하기 (Matching this or that)
교체(alternation) 메타문자 '|'로 서로 다른 문자열을 매치할 수 있어요. dog 또는 cat을 매치하려면 정규식 dog|cat을 만들어요. 앞서처럼 Perl은 문자열의 가장 이른 지점에서 정규식을 매치하려고 해요. 각 문자 위치에서 Perl은 먼저 첫 번째 대안 dog을 매치해 봐요. dog이 매치되지 않으면 다음 대안 cat을 시도해요. cat도 매치되지 않으면 매치가 실패하고 Perl은 문자열의 다음 위치로 이동해요. 몇 가지 예를 볼게요:
"cats and dogs" =~ /cat|dog|bird/; # matches "cat"
"cats and dogs" =~ /dog|cat|bird/; # matches "cat"
두 번째 정규식에서 dog이 첫 번째 대안이지만, cat이 문자열에서 더 일찍 매치될 수 있기 때문이에요.
"cats" =~ /c|ca|cat|cats/; # matches "c"
"cats" =~ /cats|cat|ca|c/; # matches "cats"
주어진 문자 위치에서 정규식 매치를 성공시키는 첫 번째 대안이 매치돼요. 여기서는 모든 대안이 첫 번째 문자열 위치에서 매치되므로, 첫 번째가 매치돼요.
그룹화와 계층적 매치 (Grouping things and hierarchical matching)
그룹화 메타문자 ()는 정규식의 일부를 하나의 단위로 취급하게 해 줘요. 정규식의 일부는 괄호로 감싸 그룹화돼요. 정규식 house(cat|keeper)는 house 다음에 cat 또는 keeper가 오는 걸 매치하라는 뜻이에요. 몇 가지 예를 더 볼게요:
/(a|b)b/; # matches 'ab' or 'bb'
/(^a|b)c/; # matches 'ac' at start of string or 'bc' anywhere
/house(cat|)/; # matches either 'housecat' or 'house'
/house(cat(s|)|)/; # matches either 'housecats' or 'housecat' or
# 'house'. Note groups can be nested.
"20" =~ /(19|20|)\d\d/; # matches the null alternative '()\d\d',
# because '20\d\d' can't match
매치 추출하기 (Extracting matches)
그룹화 메타문자 ()는 매치된 문자열의 일부를 추출할 수도 있게 해 줘요. 각 그룹에 대해 안에서 매치된 부분은 특수 변수 $1, $2 등으로 들어가요. 보통 변수처럼 쓸 수 있어요:
# extract hours, minutes, seconds
$time =~ /(\d\d):(\d\d):(\d\d)/; # match hh:mm:ss format
$hours = $1;
$minutes = $2;
$seconds = $3;
리스트 문맥에서 그룹이 있는 매치 /regex/는 매치된 값의 목록 ($1,$2,...)을 돌려줘요. 그래서 위를 이렇게 다시 쓸 수 있어요:
($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);
정규식의 그룹이 중첩돼 있으면 $1은 가장 왼쪽의 여는 괄호를 가진 그룹에, $2는 다음 여는 괄호에 들어가요. 예를 들어, 복잡한 정규식과 그 아래에 표시된 매치 변수를 볼게요:
/(ab(cd|ef)((gi)|j))/;
1 2 34
매치 변수 $1, $2, ...와 연관된 것이 백레퍼런스(backreferences) \g1, \g2, ...예요. 백레퍼런스는 정규식 안에서 쓸 수 있는 매치 변수예요:
/(\w\w\w)\s\g1/; # find sequences like 'the the' in string
$1, $2, ...는 정규식 밖에서만, \g1, \g2, ...는 정규식 안에서만 써야 해요.
반복 매치하기 (Matching repetitions)
수량자 메타문자 ?, *, +, {}는 정규식의 일부가 매치로 간주되는 반복 횟수를 정하게 해 줘요. 수량자는 지정하려는 문자, 문자 클래스, 그룹 바로 뒤에 놓아요. 다음 의미를 갖고 있어요:
a?= 'a'를 1번 또는 0번 매치a*= 'a'를 0번 이상, 즉 몇 번이든 매치a+= 'a'를 1번 이상, 즉 최소한 한 번 매치a{n,m}= 최소n번, 많아야m번 매치a{n,}= 최소n번 이상 매치a{,n}=n번 이하로 매치 (v5.34에서 추가)a{n}= 정확히n번 매치
몇 가지 예를 볼게요:
/[a-z]+\s+\d*/; # match a lowercase word, at least some space, and
# any number of digits
/(\w+)\s+\g1/; # match doubled words of arbitrary length
$year =~ /^\d{2,4}$/; # make sure year is at least 2 but not more
# than 4 digits
$year =~ /^\d{ 4 }$|^\d{2}$/; # better match; throw out 3 digit dates
이 수량자들은 정규식이 매치되는 걸 여전히 허용하면서 문자열을 최대한 많이 매치하려고 해요. 그래서:
$x = 'the cat in the hat';
$x =~ /^(.*)(at)(.*)$/; # matches,
# $1 = 'the cat in the h'
# $2 = 'at'
# $3 = '' (0 matches)
첫 번째 수량자 .*는 정규식이 매치되게 하면서 문자열을 최대한 잡아요. 두 번째 수량자 .*는 남은 문자열이 없으므로 0번 매치돼요.
더 매치하기 (More matching)
매치 연산자에 대해 알면 좋을 것들이 몇 가지 더 있어요. 전역 수정자 /g는 매치 연산자가 문자열 안에서 가능한 한 여러 번 매치하게 해 줘요. 스칼라 문맥에서 문자열에 대한 연속 매치는 /g가 매치에서 매치로 점프하면서 문자열 안의 위치를 추적해요. 위치는 pos() 함수로 얻거나 설정할 수 있어요. 예를 들어:
$x = "cat dog house"; # 3 words
while ($x =~ /(\w+)/g) {
print "Word is $1, ends at position ", pos $x, "\n";
}
이것은 다음과 같이 출력해요.
Word is cat, ends at position 3
Word is dog, ends at position 7
Word is house, ends at position 13
실패한 매치나 대상 문자열의 변경은 위치를 재설정해요. 매치 실패 후 위치가 재설정되는 걸 원하지 않으면 /c를 추가해요. 예: /regex/gc.
리스트 문맥에서 /g는 매치된 그룹의 목록을 돌려주고, 그룹이 없으면 정규식 전체의 매치 목록을 돌려줘요. 그래서:
@words = ($x =~ /(\w+)/g); # matches,
# $word[0] = 'cat'
# $word[1] = 'dog'
# $word[2] = 'house'
검색과 치환 (Search and replace)
검색과 치환은 s/regex/replacement/modifiers로 수행해요. replacement는 Perl 이중 인용 문자열로, 문자열에서 regex가 매치한 것을 대체해요. =~ 연산자는 여기서도 문자열을 s///에 연결하는 데 쓰여요. $_ 대상으로 매치한다면 $_ =~는 생략할 수 있어요. 매치가 있으면 s///는 수행된 치환 횟수를 돌려주고, 그렇지 않으면 false를 돌려줘요. 몇 가지 예를 볼게요:
$x = "Time to feed the cat!";
$x =~ s/cat/hacker/; # $x contains "Time to feed the hacker!"
$y = "'quoted words'";
$y =~ s/^'(.*)'$/$1/; # strip single quotes,
# $y contains "quoted words"
s/// 연산자로 매치 변수 $1, $2 등이 치환 표현식에서 즉시 사용 가능해요. 전역 수정자와 함께 쓰면 s///g는 문자열 안의 정규식의 모든 출현을 검색·치환해요:
$x = "I batted 4 for 4";
$x =~ s/4/four/; # $x contains "I batted four for 4"
$x = "I batted 4 for 4";
$x =~ s/4/four/g; # $x contains "I batted four for four"
비파괴 수정자 s///r는 $_(또는 =~로 치환이 묶인 다른 변수)를 수정하는 대신 치환 결과를 돌려줘요:
$x = "I like dogs.";
$y = $x =~ s/dogs/cats/r;
print "$x $y\n"; # prints "I like dogs. I like cats."
$x = "Cats are great.";
print $x =~ s/Cats/Dogs/r =~ s/Dogs/Frogs/r =~
s/Frogs/Hedgehogs/r, "\n";
# prints "Hedgehogs are great."
@foo = map { s/[a-z]/X/r } qw(a b c 1 2 3);
# @foo is now qw(X X X 1 2 3)
평가 수정자 s///e는 치환 문자열 주위에 eval{...}을 감싸고, 평가된 결과를 매치된 하위 문자열에 치환해요. 몇 가지 예를 볼게요:
# reverse all the words in a string
$x = "the cat in the hat";
$x =~ s/(\w+)/reverse $1/ge; # $x contains "eht tac ni eht tah"
# convert percentage to decimal
$x = "A 39% hit rate";
$x =~ s!(\d+)%!$1/100!e; # $x contains "A 0.39 hit rate"
마지막 예시는 s///가 s!!!, s{}{} 같은 다른 구분자, 심지어 s{}//도 쓸 수 있음을 보여줘요. 작은따옴표를 쓰면 s''', 정규식과 치환은 단일 인용 문자열로 취급돼요.
split 연산자 (The split operator)
split /regex/, string은 string을 하위 문자열 목록으로 나누고 그 목록을 돌려줘요. 정규식은 string이 나뉘는 기준이 되는 문자 시퀀스를 정해요. 예를 들어 문자열을 단어로 나누려면:
$x = "Calvin and Hobbes";
@word = split /\s+/, $x; # $word[0] = 'Calvin'
# $word[1] = 'and'
# $word[2] = 'Hobbes'
쉼표로 구분된 숫자 목록을 추출하려면:
$x = "1.618,2.718, 3.142";
@const = split /,\s*/, $x; # $const[0] = '1.618'
# $const[1] = '2.718'
# $const[2] = '3.142'
빈 정규식 //를 쓰면 문자열이 개별 문자로 나뉘어요. 정규식에 그룹이 있으면 생성된 목록에 그룹에서 매치된 하위 문자열도 포함돼요:
$x = "/usr/bin";
@parts = split m!(/)!, $x; # $parts[0] = ''
# $parts[1] = '/'
# $parts[2] = 'usr'
# $parts[3] = '/'
# $parts[4] = 'bin'
$x의 첫 문자가 정규식과 매치됐으므로, split은 목록의 앞에 빈 초기 요소를 붙였어요.
use re 'strict'
v5.22에 새로 추가된 것으로, 정규식 패턴을 컴파일할 때 그보다 더 엄격한 규칙을 적용해요. 합법적이지만 의도한 바가 아닐 수 있는 것들을 찾아낼 수 있어요.
'strict' in re를 보세요.
더 알아보기 (SEE ALSO)
이건 빠른 시작 가이드일 뿐이에요. 정규식에 대한 더 깊이 있는 튜토리얼은 perlretut, 레퍼런스 페이지는 perlre를 보세요.