//
는 일치하는 정규식을 검색하라고 Perl에게 지시한다.
=~
연산자는 좌변의 문자열과 우변의 정규식을 비교하여 정규식이 매치될 경우 참을 반환하고 그렇지 않을 경우 거짓을 반환한다.
!~
는 반대로 매치하지 않을 경우 참을 반환한다.
"Hello World" =~ /World/; # 단순한 단어의 일치 여부 검색. 일치하므로 위 expression은 true "Hello World" !~ /World/; # 반대 if ("Hello World" =~ /World/) { print "It matches\n"; } else { print "It doesn't match\n"; }문자열 리터럴이 들어갈 자리에 변수를 사용할 수 있다:
$greeting = "World"; if ("Hello World" =~ /$greeting/) { # 스트링 자리에 변수 사용 가능 print "match\n"; } else { print "not match\n"; }스페샬 변수 $_(5)에 대해 매치검사를 하는 경우,
$_ =~
부분을 생략할 수 있다:
$_ = "Hello World"; if (/World/) { # "$_ =~" 는 생략가능 print "match\n"; } else { print "not match\n"; }앞에
m
을 붙이면 //
대신에 임의의 구분자를 쓸 수 있다:
m!regexp!(6)
"Hello World" =~ m!World!; # 매치됨, 구분자는 '!' "Hello World" =~ m{World}; # 매치됨, 구분자는 '{}' "/usr/bin/perl" =~ m"/perl"; # '/usr/bin' 뒷부분에 매치됨, '/'는 평범한 문자로 간주됨.정규식은 스트링의 일부에 정확하게 매치되어야 구문이 참이 된다:
"Hello World" =~ /world/; # 일치하지 않음. 대소문자가 구분된다. "Hello World" =~ /o W/; # 일치함 "Hello World" =~ /oW/; # 일치하지 않음 "Hello World" =~ /World /; # 일치하지 않음스트링(7)의 두 곳 이상에서 정규식이 매치될 경우, 항상 가장 먼저 일치하는 곳에서 매치된다.
"Hello World" =~ /o/; # 'Hello'의 'o'에 매치됨 "That hat is red" =~ /hat/; # 'That'의 'hat'에 매치됨metacharacter(8)s 다음 캐릭터들은 문자 그대로 매치되지 않고, 정규식 표기에 사용하도록 예약되어있다:
{}[]()^$.|*+\?메타캐릭터를 일치시킬 때는 앞에 백슬래쉬를 붙인다:
"2+2=4" =~ /2+2/; # 매치되지 않는다, + 는 메타캐릭터 "2+2=4" =~ /2\+2/; # 매치된다, \+는 평범한 +로 간주된다 "The interval is [0,1)." =~ /[0,1)./ # 문법 에러! "The interval is [0,1)." =~ /\[0,1\)\./ # 매치됨 "#!/usr/bin/perl" =~ /#!\/usr\/bin\/perl/; # 매치됨 "#!/usr/bin/perl" =~ m!#\!/usr/bin/perl!; # 이렇게 하는 게 읽기 더 좋다 'C:\WIN32' =~ /C:\\WIN/; # 백슬래쉬도 메타캐릭터Escape Sequences(9)
\t
탭, \n
뉴 라인, \r
캐리지 리턴 등
\033
), 16진수로 표기(\x1B
)할 수 있다:
"1000\t2000" =~ m(0\t2) # 매치됨 "1000\n2000" =~ /0\n20/ # 매치됨 "1000\t2000" =~ /\000\t2/ # 매치되지 않음, "0"과 "\000"는 같지 않다 "cat" =~ /\o{143}\x61\x74/ # ASCII 시스템에서 매치되나, cat을 표기하는 이상한 방법이다.Perl에서 정규식은 대부분 이중 따옴표로 표시된 스트링(double-quoted string)으로 간주된다. 이스케이프 시퀀스나 변수를 처리할 때도 마찬가지이다. 정규식에 포함된 변수는 정규식의 매치 검사를 하기 전에 변수의 값으로 먼저 치환된다.
$foo = 'house'; 'housecat' =~ /$foo/; # 매치됨 'cathouse' =~ /cat$foo/; # 매치됨 'housecat' =~ /${foo}cat/; # 매치됨예제: 간단한 Unix의 grep 프로그램을 흉내내는 매우 간단한 형태
#!/usr/bin/perl $regexp = shift; # 첫번째 명령행 인자를 취함 while (<>) { # 두번째 인자를 파일명으로 하여 파일을 읽음 print if /$regexp/; # print $_ if $_ =~ /$regexp/; }
% simple_grep abba /usr/dict/words Babbage cabbage cabbages sabbath Sabbathize Sabbathizes sabbatical scabbard scabbardsanchor(10) metacharacter(11) 스트링의 '어느 지점'에 매치시킬지를 지정
"housekeeper" =~ /keeper/; # 매치됨 "housekeeper" =~ /^keeper/; # 매치되지 않음 "housekeeper" =~ /keeper$/; # 매치됨 "housekeeper\n" =~ /keeper$/; # 매치됨
^
와 $
가 동시에 쓰이면 스트링의 시작과 끝에 매치되어야 하므로, 정규식이 스트링 전체에 매치된다.
"keeper" =~ /^keep$/; # 매치되지 않음 "keeper" =~ /^keeper$/; # 매치됨 "" =~ /^$/; # ^$ 는 빈 스트링에 매치됨bert라는 이름의 친구를 찾고 있다고 가정하자:
"dogbert" =~ /bert/; # 매치되지만, 우리가 원하는 게 아님 "dilbert" =~ /^bert/; # 이런 건 매치되지 않게 했음, 그러나.. "bertram" =~ /^bert/; # 이런 게 매치됨, 여전히 문제가 있음 "bertram" =~ /^bert$/; # 매치되지 않음, 좋다 "dilbert" =~ /^bert$/; # 매치되지 않음, 좋다 "bert" =~ /^bert$/; # 매치됨, 완벽하군
$string eq 'bert'
와 같이 스트링 비교 연산을 하는게 더 효율적인다. ^...$
정규식은 아래에 나올 더 강력한 정규식 도구들을 같이 쓸 때 비로소 유용해진다.
[...]
형태
매치될 수 있는 하나 이상의 캐릭터들의 집합을 표시
/cat/; # matches 'cat' /[bcr]at/; # matches 'bat, 'cat', or 'rat' /item[0123456789]/; # matches 'item0' or ... or 'item9' "abc" =~ /[cab]/; # matches 'a' ([cab]의 순서라고 해서 'c'가 매치하는 게 아님) /[yY][eE][sS]/; # 'yes', 'Yes', 'YES' 등, 대소문자를 구분하지 않고 'yes'에 매치
/yes/i
로도 쓸 수 있다.
-]\^$
/[\]c]def/; # ']def' or 'cdef'에 매치됨 $x = 'bcr'; /[$x]at/; # 'bat', 'cat', or 'rat'에 매치됨 /[\$x]at/; # '$at' or 'xat'에 매치됨 /[\\$x]at/; # '\at', 'bat, 'cat', or 'rat'에 매치됨-(25)를 사용하여 연속된 문자들의 집합을 표시:
/item[0-9]/; # 'item0' or ... or 'item9'에 매치됨 /[0-9bx-z]aa/; # '0aa', ..., '9aa', # 'baa', 'xaa', 'yaa', or 'zaa'에 매치됨 /[0-9a-fA-F]/; # 16진수 숫자들에 매치됨 /[0-9a-zA-Z_]/; # Perl의 변수명 등에 쓰이는 "word" 캐릭터들에 매치됨
-
가 클래스 제일 앞 또는 제일 뒤에 오면 일반 문자 "-"
[-ab]
, [ab-]
, [a\-b]
는 같은 의미
/[^a]at/; # 'aat'와 'at'에는 매치되지 않고, # 그 외 모든 경우 'bat', 'cat, '0at', '%at' 등에 매치 /[^0-9]/; # 숫자가 아닌 캐릭터들에 매치 /[a^]at/; # 'aat' 또는 '^at'에 매치됨; 여기서 '^'는 보통의 문자보편적으로 사용되는 캐릭터 클래스들에 대해 별도의 축약형 제공. 5.10.0(27)부터는 이 클래스는 ASCII범위 밖의 Unicode(28) 문자에도 매치된다. 5.14.0(29)이상에서는 //a(30) 변경자를 사용하여 ASCII범위로 매치를 국한시킬 수 있다.
//aa
처럼 할 경우 더 강한 제한을 두어, ASCII문자와 비ASCII문자가 대소문자 구분없는 매치 검사에 매치되는 것을 방지할 수 있다; 이 옵션을 주지 않을 경우 유니코드 "Kelvin Sign"문자가 "k"나 "K"에 매치되게 된다)
주인장 보충: Kelvin Sign을 구글링해보니 유니코드 U+212A에 해당하고, 생김새는 "K"와 비슷하다[1]. 이것이 /i 옵션을 주었을 때는 알파벳 'k'나 'K'에 매치된다. (Perl 5.8.8에서도 마찬가지임을 확인했음) Strawberry Perl 5.12에서 테스트:이런 축약형use 5.012; $_ = chr(0x212A); # Kelvin Sign say "match /k/" if /k/; say "match /K/" if /K/; say "match /k/i" if /k/i; say "match /K/i" if /K/i;match /k/i match /K/i
\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.'
\d
와 \w
는 캐릭터들의 집합이므로, [^\d\w]
는 [\D\W]
와 같지 않다. 실제로 [^\d\w]
는 [^\w]
와 같고 이것은 [\W]
와 같다.
\w
에, 다른 하나는 \W
에 매치되는 곳
\W
에 해당하는 가상의 캐릭터가 있다고 간주
$x = "Housecat catenates house and cat"; $x =~ /cat/; # 'housecat'의 cat에 매치 $x =~ /\bcat/; # 'catenates'의 cat에 매치 $x =~ /cat\b/; # 'housecat'의 cat에 매치 $x =~ /\bcat\b/; # 스트링 마지막 'cat'의 cat에 매치어째서
.
가 매치되는 것 중 \n
는 제외되는가? 그 이유는 종종 사용자는 여러 줄에 대해 매칭을 수행하며 뉴라인 캐릭터를 무시하고자 할 때가 있기 때문이다. 예를 들어 스트링은 "\n"
한 줄을 나타내지만, 이것을 비어 있는 걸로 간주하고 싶은 것이다. 따라서 다음과 같이 판정된다:
"" =~ /^$/; # 매치됨 "\n" =~ /^$/; # 매치됨, $는 "\n" 앞에 걸린다 "" =~ /./; # 매치되지 않음; 캐릭터 하나가 필요함 "" =~ /^.$/; # 매치되지 않음; 캐릭터 하나가 필요함 "\n" =~ /^.$/; # 매치되지 않음; "\n" 이외의 캐릭터 하나가 필요함 "a" =~ /^.$/; # 매치됨 "a\n" =~ /^.$/; # 매치됨, $는 "\n" 앞에 걸린다매칭할 때 개행 문자(\n(50))를 고려하거나,
^
와 $
가 전체 스트링이 아니라 각 라인의 시작과 끝에 매치되길 바랄 때가 있다.
$x = "There once was a girl\nWho programmed in Perl\n"; $x =~ /^Who/; # 매치되지 않음, "Who"가 스트링의 시작 부분에 있지 않음 $x =~ /^Who/s; # 매치되지 않음, "Who"가 스트링의 시작 부분에 있지 않음 $x =~ /^Who/m; # 매치됨, "Who"가 두번째 라인의 시작 부분에 있음 $x =~ /^Who/sm; # 매치됨, "Who"가 두번째 라인의 시작 부분에 있음 $x =~ /girl.Who/; # 매치되지 않음, "."가 "\n"에 매치되지 않음 $x =~ /girl.Who/s; # 매치됨, "."가 "\n"에 매치됨 $x =~ /girl.Who/m; # 매치되지 않음, "."가 "\n"에 매치되지 않음 $x =~ /girl.Who/sm; # 매치됨, "."가 "\n"에 매치됨
$x = "There once was a girl\nWho programmed in Perl\n"; $x =~ /^Who/m; # matches, "Who" at start of second line $x =~ /\AWho/m; # doesn't match, "Who" is not at start of string $x =~ /girl$/m; # matches, "girl" at end of first line $x =~ /girl\Z/m; # doesn't match, "girl" is not at end of string $x =~ /Perl\Z/m; # matches, "Perl" is at newline before end $x =~ /Perl\z/m; # doesn't match, "Perl" is not at end of string
"cats and dogs" =~ /cat|dog|bird/; # "cat"에 매치됨 "cats and dogs" =~ /dog|cat|bird/; # "cat"에 매치됨
dog
가 정규식의 첫번째 후보이지만, cat
이 스트링의 더 앞쪽에서 매치가 된다.
"cats" =~ /c|ca|cat|cats/; # matches "c" "cats" =~ /cats|cat|ca|c/; # matches "cats"
"cab" =~ /a|b|c/ # "c"에 매치됨 # /a|b|c/ == /[abc]/
/(a|b)b/; # matches 'ab' or 'bb' /(ac|b)b/; # matches 'acb' or 'bb' /(^a|b)c/; # matches 'ac' at start of string or 'bc' anywhere /(a|[bc])d/; # matches 'ad', 'bd', or 'cd' /house(cat|)/; # matches either 'housecat' or 'house' /house(cat(s|)|)/; # matches either 'housecats' or 'housecat' or # 'house'. 그룹은 중첩될 수 있다. /(19|20|)\d\d/; # 년도를 나타내는 19xx, 20xx, 또는 xx에 매치 "20" =~ /(19|20|)\d\d/; # "20"은 null alternative '()\d\d'에 매치된다, # 왜냐하면 '20\d\d'은 매치될 수 없기 때문이다.
\d\d
에 매치될 것이 남아 있지 않다. 따라서 다음 후보인 빈(null) 후보로 이동하고, 이것은 "20"
이 두개의 숫자에 매치되기 때문에 성공한다.
"abcde" =~ /(abd|abc)(df|d|de)/;
# 시, 분, 초를 추출 if ($time =~ /(\d\d):(\d\d):(\d\d)/) { # match hh:mm:ss format $hours = $1; $minutes = $2; $seconds = $3; }=~(71) 구문은 scalar context(72)에서는 참/거짓을 반환하며 list context(73)에서는 매치 변수들의 리스트를 반환한다. 따라서 다음과 같이 할 수 있다:
# 시, 분, 초를 추출 ($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);그룹이 중첩되는 경우, 제일 왼쪽에 있는 여는 괄호에 의해 생긴 그룹이
$1
에 대응되고, 두번째로 나오는 여는 괄호가 $2
에 대응된다.
/(ab(cd|ef)((gi)|j))/; 1 2 34
$1
에는 'ab'로 시작하는스트링이 들어가고, $2
에는 'cd'또는 'ef'가 들어가고, $3
에는 'gi'또는 'j'가 들어가고, $4
는 $3과 마찬가지로 'gi'가 되거나, 정의되지 않는 상태로 남게 된다.
주인장 추가: 테스트 결과, 위의 예제에서 $4가 undef일 경우 $+는 $3에 대응된다. 다만 상황에 따라 매치 변수의 값이 빈 스트링 ""일 때도 있고 이 때는 $+도 이 변수에 대응된다. undef인 경우와 구분해야 함 추가로 작성해 본 예문$time = "12:34:56"; $time =~ /(\d\d):(\d\d):((\d)\d)/; 1 2 34 print "$1-$2-$3-$+-$^N"; # 12-34-56-5-56
주인장 추가: 이전 버전에서는3글자짜리 단어가 공백을 사이에 두고 두 번 연속으로 나오는 경우에 매치되는 정규식:\1
,\2
이런 식이었는데, Perl 5.14.0(78) 문서에서부터 표기법이 이렇게 바뀌었다.\g{N}
형태 자체는 Perl 5.10.0(79)에서부터 생겼음[2]
/\b(\w\w\w)\s\g1\b/; # "hey hey" "wow wow" 등에 매치같은 말이 두 번 반복된 단어를 골라내는 예:
% simple_grep '^(\w\w\w\w|\w\w\w|\w\w|\w)\g1$' /usr/dict/words beriberi booboo coco mama murmur papa
$1
,$2
,..는 정규표현식 바깥에서만, \1
,\2
,..는 정규표현식 안에서만 사용할 것.
\g{-2}
, 등.
가독성 뿐 아니라 코딩 시의 에러도 줄일 수 있다. 다음 패턴을 살펴보자:
$a99a = '([a-z])(\d)\g2\g1'; # a11a, g22g, x33x, 등에 매치됨패턴을 간편하게 스트링으로 변수에 저장했으니, 다른 패턴의 일부로 사용을 할 수 있다:
$line = "code=e99e"; if ($line =~ /^(\w+)=$a99a$/){ # 기대와 다르게 동작! print "$1 is valid\n"; } else { print "bad line: '$line'\n"; }위 코드는 의도한 대로 동작하지 않는다.
(\w+)
가 1번 그룹이 되어 버리고 $a99a에 있는 그룹들은 번호가 1씩 뒤로 밀린다. 상대적 백레퍼런스를 사용하면 이 문제를 피할 수 있다:
$a99a = '([a-z])(\d)\g{-1}\g{-2}'; # 다른 곳에 삽입되어도 안전함
$fmt1 = '(?<y>\d\d\d\d)-(?<m>\d\d)-(?<d>\d\d)'; $fmt2 = '(?<m>\d\d)/(?<d>\d\d)/(?<y>\d\d\d\d)'; $fmt3 = '(?<d>\d\d)\.(?<m>\d\d)\.(?<y>\d\d\d\d)'; for my $d qw( 2006-10-21 15.01.2007 10/31/2005 ){ if ( $d =~ m{$fmt1|$fmt2|$fmt3} ){ print "day=$+{d} month=$+{m} year=$+{y}\n"; } }
자동으로 부여되는 번호와 달리, 프로그래머가 이름을 붙이면 다음 두 가지 문제를 생각해 볼 수 있다.이 두 사안에 대해서 프로그래밍 언어나 라이브러리에 따라 다르게 처리한다. 자세한 것은 [Regex Tutorial - Named Capturing Groups - Backreference Names] 참고. Perl의 경우는 perlre 에서 짧게 언급하고 있다. 첫번째 문제의 경우, 두번 이상 사용된 이름을 가리키는 백레퍼런스는, "정의된 그룹 중 가장 왼쪽에 있는 그룹"을 가리키게 된다.
- 한 패턴 안에 동일한 이름의 캡처 그룹이 둘 이상 있으면 어떻게 되는가?
- 이름이 붙은 그룹에도 번호가 붙는가?
'abcd' =~ /(a)(?<x>b)?(c)(?<x>d)/; print "x[$+{x}]\n"; # "b" 'acd' =~ /(a)(?<x>b)?(c)(?<x>d)/; # 여기선 두번째 그룹이 매치가 안 되고, 해당 캡처 그룹에 대한 레퍼런스는 정의되지 않음. print "x[$+{x}]\n"; # "d"두번째 문제의 경우, Perl에서는 이름이 붙은 그룹도 이름이 없는 그룹들과 함께 처리되어 왼쪽에서부터 번호가 부여된다. (위 참고 링크에 따르면 .NET 스타일 정규식의 경우 일단 이름없는 그룹들부터 번호를 부여한 후, 그 다음 이름 붙은 그룹들 번호를 매긴다고)'acd' =~ /(a)(?<x>b)?(c)(?<x>d)/; print "[$1][$2][$3][$4]\n"; # [a][b][c][d], .NET스타일 정규식에선 [a][c][b][d]
if ( $time =~ /(\d\d|\d):(\d\d)|(\d\d)(\d\d)/ ){ # 시와 분을 추출하여 처리 }위 코드에서는, $1과 $2, 또는 $3과 $4 중 어느쪽이 데이타를 담고 있는지를 검사하기 위해 추가로 if 구문이 필요하다. 두번째 후보에 있는 그룹에도 번호1과 2를 부여할 수 있으면 편할 것이다. (?|...)(90) 내에 있는 각 캡처 그룹은, 각 후보들마다 동일한 번호로 시작한다. 그룹이 끝난 후에는, 후보들 중 가장 번호가 많이 부여된 그룹의 번호 다음번호부터 부여된다.
if ( $time =~ /(?|(\d\d|\d):(\d\d)|(\d\d)(\d\d))\s+([A-Z][A-Z][A-Z])/ ){ print "hour=$1 minute=$2 zone=$3\n"; }
주인장 보충:
- perlre 에 있는 예:
# before ---------------branch-reset----------- after / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x # 1 2 2 3 2 3 4/ (?| (Buster) | # $1, $2는 undef (Mimi)(Roscoe) | # $1, $2 (Ella) # $1, $2는 undef ) ( # $3 Ginger ) /x
- 위 블로그 글 하단에 있는 요점:
- Perl 은 왼쪽괄호가 코드에서 나타나는 순서에 따라 캡처 그룹에 번호를 매긴다
- alternation 안에 있는 모든 그룹에 대해 캡처 버퍼가 생성된다
- 패턴 리셋 그룹핑
(?|...)
을 사용하면 alternation 내의 각 대체 패턴마다 버퍼의 번호를 새로 시작한다- alternation 내에 named group 을 사용할 경우는 같은 번호가 매겨지는 그룹에는 같은 라벨을 붙일 것
그런데 5.14.0(91) 이전 버전에는 버그가 있다. 아래 코드는 단지 그룹 내 부분 그룹의 순서를 바꿨을 뿐인데, 결과가 달라진다.while (1) { my $input = <STDIN>; chomp $input; if ( $input =~ /(?|(a)(b)|(c))(d)/ ) { # if ( $input =~ /(?|(c)|(a)(b))(d)/ ) { print "1[$1] 2[$2] 3[$3]\n"; } }(첫번째 if 문을 사용했을 때) abd 1[a] 2[b] 3[d] cd Use of uninitialized value $2 in concatenation (.) or string at d:\Temp\test.pl line 13, <STDIN> line 2. 1[c] 2[] 3[d] (두번째 if 문을 사용했을 때) abd Use of uninitialized value $3 in concatenation (.) or string at d:\Temp\test.pl line 13, <STDIN> line 1. 1[a] 2[d] 3[] cd Use of uninitialized value $3 in concatenation (.) or string at d:\Temp\test.pl line 13, <STDIN> line 2. 1[c] 2[d] 3[]이 문제를 피하려면, 그룹에 부여되는 번호가 가장 큰 (즉 캡처 그룹의 수가 가장 많은) 후보를 제일 마지막에 쓰면 안 된다. 또는 빈 그룹()
을 채워넣어서 모든 후보의 그룹 갯수를 똑같이 맞춰주거나. 5.13.11에서 고쳐졌다고 함. (thanks to am0c) 참고링크:
$-[0]
: 전체 표현식이 매치되는 시작 위치
$+[0]
: 전체 표현식이 매치되는 끝 위치
$n
이 정의되지 않은 경우는 $-[n]
과 $+[n]
도 정의되지 않음
$x = "Mmm...donut, thought Homer"; $x =~ /^(Mmm|Yech)\.\.\.(donut|peas)/; foreach $expr (1..$#-) { print "Match $expr: '${$expr}' at position ($-[$expr],$+[$expr])\n"; } 출력: Match 1: 'Mmm' at position (0,3) Match 2: 'donut' at position (6,11)$`(96) $&(97) $'(98) - 패턴 일치 후 다음 변수를 써서, 일치된 부분과 그 앞뒤의 부분을 얻어낼 수 있다.
$x = "the cat caught the mouse"; $x =~ /cat/; # $` = 'the ', $& = 'cat', $' = ' caught the mouse' $x =~ /the/; # $` = '', $& = 'the', $' = ' cat caught the mouse'
$`
는 ''
가 된다.
$1
등의 matching variable(106)에 할당되지도 않는다. 따라서 속도가 더 빠르고, 정규식 내에서 추출되어야 할 부분과 아닌 부분을 정확히 표기하는데도 유용하다:
# 숫자에 매치, $1-$4가 설정되지만, 우리는 단지 $1만 필요 /([+-]?\ *(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)/; # 숫자에 매치, $1만 설정됨 /([+-]?\ *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)/; # 숫자에 매치, $1 = 전체 숫자, $2 = 지수부 /([+-]?\ *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE]([+-]?\d+))?)/;split(107)에서 grouping(108)이나 alternation(109)을 위해 괄호를 사용하면서 구분자 자체를 배열에 포함하지 않게 하는 데도 쓰임
$x = '12aba34ba5'; @num = split /(a|b)+/, $x; # @num = ('12','a','34','a','5') @num = split /(?:a|b)+/, $x; # @num = ('12','34','5')extended pattern(110)과 같이 사용: (?i-m:regexp) 등
?
, *
, +
, { }
/[a-z]+\s+\d*/; # 소문자로 된 단어, 하나 이상의 공백, 그 다음 임의 갯수의 숫자들 /(\w+)\s+\g1/; # 임의 글자의 단어가 두 번 반복되는 형태 /y(es)?/i; # 'y', 'Y', 또는 대소문자 구분없이 'yes'에 매치 $year =~ /^\d{2,4}$/; # 년도는 최소 2자리 최대 4자리 $year =~ /^\d{4}$|^\d{2}$/; # 더 나은 형태. 3자리 숫자는 매치되지 않게 함 $year =~ /^\d{2}(\d{2})?$/; # 다른 형태. 이 경우는 마지막 두 자리가 $1에 캡처됨
% simple_grep '^(\w+)\g1$' /usr/dict/words # 더 쉬워졌죠? beriberi booboo coco mama murmur papa이 수량자들은 maximal match(119) (or, greedy(120)) quantifier 이다 - 전체 정규식 매치가 성공할 수 있는 선에서, 가능한 가장 긴 스트링(121)에 매치된다. 다음 두 매치를 비교:
$x = "the cat in the hat"; $x =~ /^(.*)(cat)(.*)$/; # 매치됨, # $1 = 'the ' # $2 = 'cat' # $3 = ' in the hat' $x = "the cat in the hat"; $x =~ /^(.*)(at)(.*)$/; # 매치됨, # $1 = 'the cat in the h' # $2 = 'at' # $3 = '' (0개의 캐릭터가 매치)
a|b|c...
형태의 alternation(123)에서, 전체 정규식이 일치하게 할 수 있는 후보들 중 가장 왼쪽에 있는 것을 사용한다.
$x = "The programming republic of Perl"; $x =~ /^(.+)(e|r)(.*)$/; # matches, # $1 = 'The programming republic of Pe' # $2 = 'r' (e|r)에서 r이 사용된다. # $3 = 'l'
'T'
에서부터 매치되고, 첫번째 수량자 부분이 가장 긴 스트링을 사용하게 되므로 두번째 그룹에서 왼쪽 후보인 e
가 아니라 r
이 매치된다.
$x =~ /(m{1,2})(.*)$/; # matches, # $1 = 'mm' # $2 = 'ing republic of Perl'
m{1,2}
는 최대로 매치할 수 있는 mm
에 매치된다.
$x =~ /.*(m{1,2})(.*)$/; # matches, # $1 = 'm' # $2 = 'ing republic of Perl'
.*
가 최대한 많이 사용하므로 두번째 수량자 m{1,2}
에는 한 글자 'm'
만 매치된다.
$x =~ /(.?)(m{1,2})(.*)$/; # matches, # $1 = 'a' # $2 = 'mm' # $3 = 'ing republic of Perl'
.?
는 매치가 가능한 위치에서 최댓값인 한 글자를 사용하므로 'programming'의 'a'
에 매치가 되고, m{1,2}
는 두 m
에 매치된다.
"aXXXb" =~ /(X*)/; # 매치됨, $1 = ''
X*
는 스트링의 시작 부분에서 'X'
의 0회 반복에 매치되어 버린다. 최소 하나의 'X'에 매치되길 원하면 X+
를 사용하라.
$x = "The programming republic of Perl"; $x =~ /^(.+?)(e|r)(.*)$/; # matches, # $1 = 'Th' # $2 = 'e' # $3 = ' programming republic of Perl'
^
와 두번째 그룹의 alternation을 만족시킬 수 있는 최소 길이 스트링은 Th
이고, e|r
은 e
가 매치되고, 마지막 .*
는 나머지 스트링 전부를 사용한다.
$x =~ /(m{1,2}?)(.*?)$/; # matches, # $1 = 'm' # $2 = 'ming republic of Perl'
m{1,2}?
는 하나의 'm'만 매치된다. 두번째 수량자 .*?
는 0개의 캐릭터에 매치되는 걸 더 원했겠지만, 여기서는 $(134) 때문에 제약을 받아 나머지 스트링 전부에 매치된다.
$x =~ /(.*?)(m{1,2}?)(.*)$/; # matches, # $1 = 'The progra' (.*?)이지만 $1=''가 아니다!! 원칙0이 적용 # $2 = 'm' # $3 = 'ming republic of Perl'
^
앵커가 없기 때문에 첫번째 minimal quantifier .*?
가 (첫번째 'm'바로 앞에 있는) 빈 스트링에 매치될 거라 기대했을 수 있지만, 원칙0이 적용된다. 전체 정규식을 스트링의 제일 첫부분부터 매치시키는 게 가능하기 때문에 실제로 그렇게 매치시키고, 첫번째 수량자는 첫번째 'm'바로 앞 부분까지 스트링 전부에 대응된다. 두번째 수량자는 하나의 'm'에 매치되고, 세번째 것은 나머지 스트링 전부에 매치된다.
$x =~ /(.??)(m{1,2})(.*)$/; # matches, # $1 = 'a' # $2 = 'mm' # $3 = 'ing republic of Perl'
.??
가 매치될 수 있는 가장 앞부분이 'a'
이므로 거기에 매치된다.
$x = "the cat in the hat"; $x =~ /^(.*)(at)(.*)$/; # matches, # $1 = 'the cat in the h' # $2 = 'at' # $3 = '' (0 matches)
/(a|b+)*/;
/^\w+\s+\w+$/; # 단어, 공백, 단어우리가 찾고자 하는 패턴에 해당되지 않는
"abc "
나 "abcdef "
등에 이 정규식을 적용할 경우, 스트링의 각 캐릭터마다 백트랙하게 될 것이다. 그러나 절대 매치되지 않을 것을 알고 있다.
5.10.0(137)부터는 possessive(138) quantifier 제공:
+
를 붙임
a{0,1}+
와 같음
a{0,}+
와 같음
a{1,}+
와 같음
/"(?:[^"\\]++|\\.)*+"/;
주인장 추가: possessive quantifier에 대해 perlretut 문서의 내용이 잘 와닿지 않는다. 다음 두 문서를 참고하면 좋다.일단, 독점 수량자는 greedy한 수량자와 서로 다른 매치 결과를 낼 수 있으니 주의하라:
- [Regex Tutorial - Possessive Quantifiers] - 설명이 잘 나와 있음
- perlre
'aaaa' =~ /a++a/독점적 수량자가 유용한 경우의 예는 다음과 같다.
- 위 패턴은 매치되지 않는다.
a++
가'aaaa'
전부에 매치되고, 그 다음 부분인a
에 매치될 게 남지 않는다.a+
를 썼다면 이때 백트래킹하면서 'a'하나를 내어놓아서 다음 패턴에 매치되게 하였겠지만, 독점적 수량자는 백트래킹을 하지 않는다.'aaaa' =~ /a++b/따라서 독점적 수량자를 사용할 경우에는, 독점적 수량자를 적용하는 부분의 패턴이, 그 뒷부분에 있는 패턴과 매치되지 않는 게 확실한지 확인해야 한다. 위 예에서는
- 위 패턴 역시 매치하지 않는다. 그러나 greedy 수량자를 썼을 경우는
a+
정규식은 처음에 'aaaa'에 매치되고,b
를 매치할 수 없으므로 한 글자를 백트래킹하여 'aaa'에 매치되고, 마찬가지로 'aa','a'에 매치되면서 계속b
를 매치시키려고 하며, 매번 무의미하게 실패하게 된다. 그러나 독점적 수량자를 사용한 경우a++
는 첫 시도에 'aaaa'에 매치된 후에, 그 위치에서 더 이상 백트래킹을 하지 않게 하므로,b
가 스트링의 끝에 대응되어서 매치가 안 되는 것을 확인하는 순간 매치 실패를 판정한다. 매우 효율적이다. (단, 여기서 전체 검사가 완전히 종료되는 건 아니다. 스트링의 그 다음 위치, 즉 두번째 a부터 시작해서 'aaa'를 대상으로 다시 시도하게 된다)a++
의a
가 뒤에 있는 패턴b
와 일치될 수 없다. 즉, 'a++
을 매치시키는 동안, 실수로 스트링 내에 있는 'b'를 잡아먹어 버렸을 리가 없다'는 것이다. 반면.++b
같은 패턴은.
가b
에도 매치되므로 의도하지 않은 결과를 낼 수 있다.
/[+-]?\d+/; # 정수에 매치
\d*\.\d*
를 쓰면 안된다. ("."가 매치되어 버릴 수 있다)
/[+-]?\d+\./; # 1., 321., etc. /[+-]?\.\d+/; # .1, .234, etc. /[+-]?\d+\.\d+/; # 1.0, 30.56, etc.세 가지 후보를 결합하여 alternation(145) 형태로 만들 수 있다.
/[+-]?(\d+\.\d+|\d+\.|\.\d+)/; # 지수부가 없는 부동소수 # "\d+\.\d+"가 제일 앞에 와야만 한다.지수가 있는 경우를 고려한다. 지수부는 정수와 소숫점이 있는 소수 양쪽에 다 붙을 수도 있다. 따라서 앞에 매치되는 숫자에 소숫점이 있는지 없는지에 무관하며, 유효숫자부와 별개로 처리할 수 있다.
/^(optional sign)(integer | f.p. mantissa)(optional exponent)$/;지수부의 형태는
e
또는 E
뒤에 정수가 오는 것이다.
/[eE][+-]?\d+/; # 지수부따라서 전체 정규표현식은
/^[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)([eE][+-]?\d+)?$/; # 짠~위와 같이 복잡한 정규식은, //x(146) modifier(147)를 사용하여 공백과 주석을 추가하여 읽기 쉽게 만들 수 있다.
/^ [+-]? # 먼저, 부호에 매치 ( # 그 다음 정수 또는 소수의 유효숫자부에 매치 \d+\.\d+ # a.b 형태의 유효숫자 |\d+\. # a. 형태의 유효숫자 |\.\d+ # .b 형태의 유효숫자 |\d+ # a 형태의 정수 ) ([eE][+-]?\d+)? # 끝으로, 추가적으로 올 수 있는 지수부에 매치 $/x;이 때 정규식 내의 스페이스를 넣고 싶으면
\
또는 [ ]
로 표기한다. 마찬가지로 #
은 각각 \#
또는 [#]
으로 표기한다.
/^ [+-]?\ * # 먼저, 부호와 *공백*에 매치 ( # 그 다음 정수 또는 소수의 유효숫자부에 매치 \d+\.\d+ # a.b 형태의 유효숫자 |\d+\. # a. 형태의 유효숫자 |\.\d+ # .b 형태의 유효숫자 |\d+ # a 형태의 정수 ) ([eE][+-]?\d+)? # 끝으로, 추가적으로 올 수 있는 지수부에 매치 $/x;alternation 그룹의 1,2,4번째 후보는 다
\d+
로 시작하므로, 이것을 뽑아내어 더 단순하게 만들 수 있다.
/^ [+-]?\ * # 먼저, 부호와 공백에 매치 ( # 그 다음 정수 또는 소수의 유효숫자부에 매치 \d+ # a로 시작하면서... ( \.\d* # a.b 또는 a. 형태의 유효숫자 )? # ?는 a 형태의 정수가 오는 경우를 고려한 것 |\.\d+ # .b 형태의 유효숫자 ) ([eE][+-]?\d+)? # 끝으로, 추가적으로 올 수 있는 지수부에 매치 $/x;또는 압축된 형태로 다시 쓸 수 있다:
/^[+-]?\ *(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;이렇게 해서 정규식을 완성하였다. 다시 정리하면 정규식을 만들기 위하여 다음의 과정을 거쳤다.
@pattern = ('Seuss'); while (<>) { print if m'@pattern'; # 문자 그대로 '@pattern'에 매치된다, 'Seuss'가 아니라. }스트링(159)에서와 마찬가지로
m''
는 아포스트로피처럼 동작하고, 그 외 다른 m
구분자들은 따옴표처럼 동작한다.
정규표현식을 평가했더니 빈 스트링인 경우, 마지막으로 매치에 성공했던 정규식이 대신 사용된다1
"dog" =~ /d/; # 'd'에 매치됨 "dogbert" =~ //; # 이전에 사용되었던 'd' 정규식에 매치됨
//g
: 글로벌 매칭. 한 스트링 안에서 매칭을 가능한 한 여러번 반복 수행.
$x = "cat dog house"; # 3 words $x =~ /^\s*(\w+)\s+(\w+)\s+(\w+)\s*$/; # matches, # $1 = 'cat' # $2 = 'dog' # $3 = 'house'단어의 갯수를 모른다면? 단순한 정규식
(\w+)
를 구성한 후 /(\w+)/g
를 사용하여 매치되는 모든 곳에 대해 루프를 돌아라:
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매치에 실패하거나 타겟스트링이 바뀌면 포지션은 리셋된다2. 매치에 실패해도 리셋되지 않게 하려면
/regexp/gc
와 같이 //c(164) modifier를 같이 사용한다. 현재 포지션 값은 정규식이 아니라 각 스트링에 결합되어 있다. 서로 다른 스트링은 서로 다른 포지션 값을 갖고 있고, 각각을 독립적으로 설정하거나 읽을 수 있다.
list context(165)에서 //g(166)는 매치된 그룹들의 리스트를 반환한다. 패턴 내에 그룹이 없을 경우 전체 정규식에 일치하는 문자열의 리스트를 반환한다.
@words = ($x =~ /(\w+)/g); # matches, # $word[0] = 'cat' # $word[1] = 'dog' # $word[2] = 'house'\G(167) - 직전에 사용된 //g(168)에 의해 일치한 부분의 끝에 일치한다. 현재는 정규식의 제일 첫 부분에 사용되었을 때만 제대로 지원이 된다.
\G
를 써서 문맥에 의존하는 매칭을 할 수 있다:
$metric = 1; # 미터법을 쓰도록 설정 ... $x = <FILE>; # 측정값을 읽음 $x =~ /^([+-]?\d+)\s*/g; # 수치 부분을 읽음 $weight = $1; if ($metric) { # 에러 체크 print "Units error!" unless $x =~ /\Gkg\./g; } else { print "Units error!" unless $x =~ /\Glbs\./g; } $x =~ /\G\s+(widget|sprocket)/g; # 계속 진행
//g
와 \G
를 조합하여, 스트링의 일부를 먼저 처리하고 그 다음 무엇을 할 것인지 Perl 논리구조를 사용하여 결정할 수 있다.
\G
는 또한 고정된 길이의 레코드를 정규식으로 처리할 때 유용하다. DNA 영역에서 TGA
코돈(codon, 3-문자 순열)을 모두 찾는 경우의 예: DNA 단편을 3글자짜리 레코드들의 순열로 생각할 수 있다.
# expanded, this is "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; $dna =~ /TGA/;위 매치는 아무 위치에서나
TGA
에 매치되므로 안 된다.
개선된 풀이는
while ($dna =~ /(\w\w\w)*?TGA/g) { # note the minimal *? print "Got a TGA stop codon at position ", pos $dna, "\n"; }다음과 같이 출력된다:
Got a TGA stop codon at position 18 Got a TGA stop codon at position 2318번째 캐릭터 포지션은 맞다. 그런데 23번은 틀렸다. 위의 정규식은 마지막으로 제대로 매치된 시점 이후부터 제대로 동작하지 않는다. 그 이후 정규식이
TGA
코돈에 매치에 실패하고, 스트링의 포지션을 한 글자 이동하여 재시도하게 된다. 이 문제를 해결하는 방법은 \G
를 사용하여 코돈 경계 부분에 앵커를 설정하는 것이다:
while ($dna =~ /\G(\w\w\w)*?TGA/g) { print "Got a TGA stop codon at position ", pos $dna, "\n"; }출력:
Got a TGA stop codon at position 18위의 예제는, 원하는 것에 매치하는 것 뿐 아니라 원하지 않는 것을 매치되지 않게 하는 것도 중요함을 보여준다. (//o(169), //d(170), //l(171) 등 정규식에서 사용 가능한 modifier가 몇 개 더 있으나, 이 문서의 범위를 벗어난다)
s/regexp/replacement/modifier
s///
를 =~(173)로 연결
$_ =~
는 생략가능
$x = "Time to feed the cat!"; $x =~ s/cat/hacker/; # $x 는 "Time to feed the hacker!" if ($x =~ s/^(Time.*hacker)!$/$1 now!/) { $more_insistent = 1; } $y = "'quoted words'"; $y =~ s/^'(.*)'$/$1/; # 작은따옴표를 벗겨냄 # $y 는 "quoted words"
$1
등은 곧바로 replacement 자리에 사용할 수 있다.
$x = "I batted 4 for 4"; $x =~ s/4/four/; # 한번만 치환: # $x 는 "I batted four for 4" $x = "I batted 4 for 4"; $x =~ s/4/four/g; # 전부 치환: # $x 는 "I batted four for four"이 튜토리알 문서에서 'regexp'라는 표현보다 'regex'가 더 좋다면, 다음 프로그램을 써서 치환할 수 있다3:
% cat > simple_replace #!/usr/bin/perl $regexp = shift; $replacement = shift; while (<>) { s/$regexp/$replacement/g; print; } ^D % simple_replace regexp regex perlretut.pod
simple_replace
에서는 s///g
를 써서 각 라인에 나타나는 모든 regexp를 치환환다.
simple_grep
과 마찬가지로 print
와 s/$regexp/$replacement/g
는 암시적으로 $_
에 대해 수행되었다.
s///
가 원본 변수를 수정해버리는 것을 막을 수 있다. s///r
은 치환된 횟수를 반환하는 것이 아니라 최종적으로 치환된 스트링을 반환한다.
$x = "I like dogs."; $y = $x =~ s/dogs/cats/r; print "$x $y\n";
$x
의 값이 변하지 않았고, 치환된 최종 결과는 $y
에 담긴다.
$x = "I like dogs."; $y = $x =~ s/elephants/cougars/r; print "$x $y\n"; # prints "I like dogs. I like dogs."
s///r
을 써서 연쇄 치환을 할 수 있다:
$x = "Cats are great."; print $x =~ s/Cats/Dogs/r =~ s/Dogs/Frogs/r =~ s/Frogs/Hedgehogs/r, "\n"; # prints "Hedgehogs are great."치환 연산에서만 사용가능한 evaluation modifier s///e(178)
$x = "Bill the cat"; $x =~ s/(.)/$chars{$1}++;$1/eg; # 마지막 $1는 각 문자를 그 문자 자신으로 치환 print "frequency of '$_' is $chars{$_}\n" foreach (sort {$chars{$b} <=> $chars{$a}} keys %chars);출력:
frequency of ' ' is 2 frequency of 't' is 2 frequency of 'l' is 2 frequency of 'B' is 1 frequency of 'c' is 1 frequency of 'e' is 1 frequency of 'h' is 1 frequency of 'i' is 1 frequency of 'a' is 1
s///
도 m//
처럼 다양한 구분자를 쓸 수 있다.
s!!!
, s{}{}
, s{}//
등
split /regexp/, string, limit
$x = "Calvin and Hobbes"; @words = split /\s+/, $x; # $word[0] = 'Calvin' # $word[1] = 'and' # $word[2] = 'Hobbes'
$x = "/usr/bin/perl"; @dirs = split m!/!, $x; # $dirs[0] = '' # $dirs[1] = 'usr' # $dirs[2] = 'bin' # $dirs[3] = 'perl' @parts = split m!(/)!, $x; # $parts[0] = '' # $parts[1] = '/' # $parts[2] = 'usr' # $parts[3] = '/' # $parts[4] = 'bin' # $parts[5] = '/' # $parts[6] = 'perl'
$x = "perl"; $string =~ /\u$x/; # $string의 'Perl'에 매치 $x = "M(rs?|s)\\."; # 백슬래쉬를 두 번 쓴 것에 유의 $string =~ /\l$x/; # 'mr.', 'mrs.', 'ms.'에 매치\L(187) \U(188) - 뒤에 이어지는 (\E(189)를 만나거나, 또다른
\U
나 \L
을 만나거나, 그 외에는 스트링의 끝까지) 전체 문자열을 소문자 또는 대문자로 변환
$x = "This word is in lower case:\L SHOUT\E"; $x =~ /shout/; # 매치됨 $x = "I STILL KEYPUNCH CARDS FOR MY 360" $x =~ /\Ukeypunch/; # matches punch card string
\cZ
)
\Q(191)...\E(192)
$x = "\QThat !^*&%~& cat!"; $x =~ /\Q!^*&%~&\E/; # check for rough language"\Q", "\L", "\l", "\U", "\u", "\E"는 사실 큰따옴표 인용 문법의 일부이지, 정규표현식 문법의 일부가 아니다. 이것들이 프로그램에 직접 삽입된 정규식에 나타날 경우는 제대로 동작하겠지만, 스트링 안에 들어 있다가 패턴 내에서 삽입될 경우는 동작하지 않는다.
(주인장 보충:) 바로 위 문단의 말은, (주인장이 제대로 이해했다면), 다음과 같은 코드로 확인할 수 있다:Perl 5.6.0(193)부터는 정규표현식에서 Unicode(194)를 지원my $str1 = "\uhello"; # $str1 = 'Hello' my $str2 = '\uhello'; # $str2 = '\uhello' say "match" if 'Hello' =~ /$str1/; # 매치됨 say "match" if 'Hello' =~ /$str2/; # 런타임 에러match Unrecognized escape \u passed through in regex; marked by <-- HERE in m/\u <-- HERE hello/ at ...$str2 변수 안에 들어있는 "\u"는 정규식에서는 인식하지 못하는 이스케이프 시퀀스로 취급되어 에러가 난다. perlretut 문서에 위 문단이 추가된 시점은 [여기서 처음], [여기서 개정]
\x hex
형태로 쓰는 것은 255를 넘지 않기 때문이다.
/\x{263a}/; # match a Unicode smiley face :)
use utf8
을 적어줘야 했으나, 현재는 대부분의 유니코드 처리와 관련해서는 명시적인 utf8 프라그마를 써 줄 필요가 없다. (유일하게 문제가 되는 부분은, 사용자의 펄 스크립트가 유니코드로 작성되어 있고 UTF-8 인코딩으로 저장되어 있을 때는 명시적으로 use utf8 을 해주어야 한다는 점이다.)
name
은 표준에 명시된 유니코드 문자의 이름이다.
use charnames ":full"; # use named chars with Unicode full names $x = "abc\N{MERCURY}def"; $x =~ /\N{MERCURY}/; # matches
use charnames ':full'; print "\N{GREEK SMALL LETTER SIGMA} is called sigma.\n"; use charnames ":short"; print "\N{greek:Sigma} is an upper-case sigma.\n"; use charnames qw(greek); print "\N{sigma} is Greek sigma\n";
NamesList.txt
에 들어 있다.8 (http://www.unicode.org/Public/UNIDATA/ 에서 얻을 수 있음)
use 5.012
(또는 그보다 높은 버전) 또는 use feature 'unicode_strings'
pragma(204)를 써서, 프라그마를 사용한 스코프 내에서 묵시적으로 //u modifier를 쓰라고 할 수 있다)
\p{name}
을 제외한 나머지
use charnames ":full"; # use named chars with Unicode full names $x = "BOB"; $x =~ /^\p{IsUpper}/; # matches, uppercase char class $x =~ /^\P{IsUpper}/; # doesn't match, char class sans uppercase $x =~ /^\p{IsLower}/; # doesn't match, lowercase char class $x =~ /^\P{IsLower}/; # matches, char class sans lowercasePerl에서 사용하는 클래스 이름들과, 전통적인 유닉스 클래스들과의 관계:
Perl 클래스이름 유니코드 클래스 이름 또는 정규 표현식 IsAlpha /^[LM]/ IsAlnum /^[LMN]/ IsASCII $code <= 127 IsCntrl /^C/ IsBlank $code =~ /^(0020|0009)$/ || /^Z[^lp]/ IsDigit Nd IsGraph /^([LMNPS]|Co)/ IsLower Ll IsPrint /^([LMNPS]|Co|Zs)/ IsPunct /^P/ IsSpace /^Z/ || ($code =~ /^(0009|000A|000B|000C|000D)$/ IsSpacePerl /^Z/ || ($code =~ /^(0009|000A|000C|000D|0085|2028|2029)$/ IsUpper /^L[ut]/ IsWord /^[LMN]/ || $code eq "005F" IsXDigit $code =~ /^00(3[0-9]|[46][1-6])$/공식적인 유니코드 클래스 이름을 \p(209)나 \P(210)와 같이 사용할 수도 있다.
\p{L}
- 유니코드 'letters'
\p{Lu}
- 대문자
\P{Nd}
- 숫자가 아닌 것들
\pM
유니코드 'marks'
\p{...}
(특정 집합에 포함되는지) 또는 \P{...}
(포함되지 않는지)으로 테스트할 수 있다.
\p{Latin}
, \p{Greek}
, \p{Katakana}
\p{...}
과 같은 단일 형태 외에, \p{name=value}(211)또는 \p{name:value}(212) 형태의 복합 형태를 사용할 경우도 있다.
=
와 :
둘 다 사용가능
\p{Script=Latin}
, \p{Script:Greek}
, \P{script=katakana}
등이 된다 (중괄호 안에서는 대소문자 무관).
A + COMBINING RING
- 덴마크에서 A위에 동그라미가 있는 문자 Å
name
은 POSIX 클래스
[:upper:]
는 \p{IsUpper}
와 동일
^
.
[:^digit:]
- \D(220) 또는 유니코드에서 \P{IsDigit}
[...]
안에서만 사용 가능하다:
/\s+[abc[:digit:]xyz]\s*/; # match a,b,c,x,y,z, or a digit /^=item\s[[:digit:]]/; # match '=item', # followed by a space and a digit /\s+[abc\p{IsDigit}xyz]\s+/; # match a,b,c,x,y,z, or a digit /^=item\s\p{IsDigit}/; # match '=item', # followed by a space and a digit
qr/string/
- string
을 정규표현식으로 간주하여 컴파일한 후 변수에 할당할 수 있는 형태로 변환
$reg = qr/foo+bar?/; # reg는 컴파일된 정규식을 저장
$x = "fooooba"; $x =~ $reg; # 매치됨, /foo+bar?/와 같다 $x =~ /$reg/; # 형태만 다르지 동일함
$x =~ /(abc)?$reg/; # 여전히 매치됨다양한 구분자 사용가능
qr!!
, qr{}
, qr~~
등
qr''
어떠한 치환도 안 됨
simple_grep
을 확장한 프로그램. 여러 패턴을 순차적으로 검색하며, 한 패턴이 발견되면 다음 패턴으로 넘어간다.
#!/usr/bin/perl # grep_step - match <number> regexps, one after the other # usage: grep_step <number> regexp1 regexp2 ... file1 file2 ... $number = shift; $regexp[$_] = shift foreach (0..$number-1); @compiled = map qr/$_/, @regexp; while ($line = <>) { if ($line =~ /$compiled[0]/) { print $line; shift @compiled; last unless @compiled; } }
% grep_step 3 shift print last grep_step $number = shift; print $line; last unless @compiled;
@compiled
변수에 저장함으로써 재컴파일할 필요가 없이 루프를 돌며 정규식들을 사용할 수 있다.10
simple_grep
의 개선판: 여러 패턴을 매칭하는 프로그램
#!/usr/bin/perl # multi_grep - match any of <number> regexps # usage: multi_grep <number> regexp1 regexp2 ... file1 file2 ... $number = shift; $regexp[$_] = shift foreach (0..$number-1); $pattern = join '|', @regexp; while ($line = <>) { print $line if $line =~ /$pattern/; }
% multi_grep 2 shift for multi_grep $number = shift; $regexp[$_] = shift foreach (0..$number-1);가끔은, 분석할 입력을 패턴으로 구성하고, 허용되는 값들을 매칭 연산의 좌변에 두는 게 더 나을 때가 있다. 이렇게 다소 역설적으로 들리는 상황의 예로, 입력으로 명령어를 받고 이 명령어는 사용 가능한 명령어들 중 하나여야 한다고 하자. 또한 명령어들은 혼동의 여지가 없는 한 축약해서 쓸 수 있다고 하자:
#!/usr/bin/perl # keymatch $kwds = 'copy compare list print'; while( $command = <> ){ $command =~ s/^\s+|\s+$//g; # 앞뒤에 공백을 제거 if( ( @matches = $kwds =~ /\b$command\w*/g ) == 1 ){ print "command: '@matches'\n"; } elsif( @matches == 0 ){ print "no such command: '$command'\n"; } else { print "not unique: '$command' (could be one of: @matches)\n"; } }
% keymatch li command: 'list' co not unique: 'co' (could be one of: copy compare) printer no such command: 'printer'입력을 각 키워드들에 일일이 매치하지 않고, 키워드들을 합친 집합을 입력에 매치하였다.
$kwds =~ /\b($command\w*)/g
연산은 한번에 여러가지 일을 수행한다.
\b
)
\w*
로 인하여 앞부분만 축약해서 입력할 수 있게 하고
scalar @matches
)
(?char...)
형태
/(?# Match an integer:)[+-]?\d+/;
/(?i)yes/; # 대소문자 구분 없이 'yes'에 매치 /yes/i; # 위와 동일 /(?x)( # 정수를 나타내는 정규식 [+-]? # 선택적으로 올 수 있는 부호에 매치 \d+ # 숫자의 시퀀스에 매치 ) /x;
$pattern[0] = '(?i)doctor'; $pattern[1] = 'Johnson'; ... while (<>) { foreach $patt (@pattern) { print if /$patt/; } }2) 패턴 내의 특정 그룹에만 변경자의 효과를 지정할 수 있다. (//p(234)는 예외. 이것은 전체 정규식에 적용된다)
/Answer: ((?i)yes)/; # matches 'Answer: yes', 'Answer: YES', etc.현재 적용되고 있는 modifier의 효과를 없애기:
(?-i)
등
여러 modifier를 동시에 사용하기: (?s-i)
등
삽입된 modifier는 non-capturing(235) 그룹이다. 예를 들어 (?i-m:regexp)
는 regexp
에 대소문자 구분 없고 multi-line 모드를 끈 상태에서 매치되는, 캡처되지 않는 그룹이다.
주인장 보충 - [Let perl create your regex stringification | The Effective Perler]의 내용 정규표현식을 스트링으로 표현(stringify)할 때, 이전에는 적용 안 된 옵션들을 명시하는 형태였다:$ perl5.12.2 -le 'print qr/Buster|Mimi/;' (?-xism:Buster|Mimi)이 경우 문제점은, Perl 버전이 올라가면서 새로운 변경자가 추가되면, 스트링 표현에 그 변경자가 추가되어야 하므로 동일한 정규표현식이 버전에 따라 서로 다르게 표현될 있다는 점이다 5.14.0부터는 적용되는 옵션들만을 표시하기 때문에 항상 동일하게 표현된다.$ perl5.13.6 -le 'print qr/Buster|Mimi/i' (?^i:Buster|Mimi)프로그래머 입장에서는, 애초에 스트링 표현을 명시적으로 하지 말고 Perl이 하도록 하면 딱히 신경쓰지 않아도 된다
[abc}]
는 매치될 때 스트링의 캐릭터 하나를 먹으며, Perl은 매치 후 스트링의 그 다음 캐릭터 위치로 이동한다. 그러나 매치될 때 캐릭터들을 먹지(즉 캐릭터 포지션을 이동시키지) 않는 요소들이 일부 있다. 위에서 봤던 anchor(238)들이 그 예다. 앵커 ^(239)는 라인의 시작 부분에 매치되나, 어떤 캐릭터도 삼키지 않는다. \b(240)도 유사하게 \w
에 매치되는 캐릭터와 매치되지 않는 캐릭터가 접한 위치에 매치되지만, 캐릭터를 삼키진 않는다. 앵커는 zero-width(241) assertion(242)의 예이다
^
는 뒤쪽을 살펴보고 뒤쪽에 아무 캐릭터도 없는지 확인한다. $
는 앞쪽을 살펴보고 앞에 캐릭터가 남아 있지 않는 것을 확인한다. \b
는 앞뒤를 다 살펴보고, 앞뒤에 있는 캐릭터들이 word인지 여부가 서로 다른지 확인한다.
lookahead와 lookbehind는 앵커 개념을 일반화한 것이며, zero-width assertion으로써 우리가 테스트하려는 캐릭터가 무엇인지 명시할 수 있다.
$x = "I catch the housecat 'Tom-cat' with catnip"; $x =~ /cat(?=\s)/; # matches 'cat' in 'housecat' @catwords = ($x =~ /(?<=\s)cat\w+/g); # matches, # $catwords[0] = 'catch' # $catwords[1] = 'catnip' $x =~ /\bcat\b/; # matches 'cat' in 'Tom-cat' $x =~ /(?<=\s)cat(?=\s)/; # doesn't match; no isolated 'cat' in # middle of $x
$x = "foobar"; $x =~ /foo(?!bar)/; # doesn't match, 'bar' follows 'foo' $x =~ /foo(?!baz)/; # matches, 'baz' doesn't follow 'foo' $x =~ /(?<!\s)foo/; # matches, there is no \s before 'foo'
/\s+/
만 사용하는 걸로는 제대로 분리되지 않는다. 분리할 위치를 lookahead와 lookbehind를 사용하여 지정해 주고 있다:
$str = "one two - --6-8"; @toks = split / \s+ # 연속된 공백 | (?<=\S) (?=-) # 공백이 아닌 문자와 '-'사이 | (?<=-) (?=\S) # '-'와 공백이 아닌 문자 사이 /x, $str; # @toks = qw(one two - - - 6 - 8)
$x = "ab"; $x =~ /a*ab/; # 매치됨
a*
는 일단 스트링의 a
를 가로채어 간다. 그러나 이렇게 하면 전체 정규표현식이 매치가 되지 않으므로 앞으로 되돌아간 후 a
를 내어놓고 자신은 빈 스트링에 매치된다. 즉 a*
가 매치되는 부분은 정규식의 나머지 부분이 매치되는 부분에 의존적이다.
$x =~ /(?>a*)ab/; # 매치되지 않음!
(?>a*)
는 정규식의 나머지 부분을 고려하지 않고 자신이 매치될 수 있는 최대한의 스트링을 가로채어 간다. 따라서 정규식의 나머지 부분 ab
는 매치가 되지 않는다. (?>a*)
는 독립적이므로, 백트래킹이 생기지 않고 이 부분표현식은 자신이 매치된 a
를 내어놓지 않는다.
$x = "ab"; $x =~ /a*/g; # 매치됨, 'a'를 먹어버림 $x =~ /\Gab/g; # 매치되지 않음, 매치할 'a'가 남아있지 않다독립적 부분표현식이 백트래킹을 방지하는 특성은, 검색 소요 시간을 줄이는 데 유용하다
$x = "abc(de(fg)h"; # 쌍이 맞지 않는 괄호들 $x =~ /\( ( [^()]+ | \([^()]*\) )+ \)/x;
[^()]+
는 괄호가 없는 서브스트링에, 두번째 \([^()]*\)
는 괄호로 둘러싸인 서브스트링에 매치된다.
(a+|b)+
형태로 중첩되어 있고, 파트1에서 얘기했듯이 이것은 전체 스트링에서 매치되는 부분이 없을 경우 검색시간이 지수적으로 증가함
$x =~ /\( ( (?>[^()]+) | \([^()]*\) )+ \)/x;
(?>[^()]+)
부분은 가능한 많은 양의 스트링을 삼켜버리고 내어놓지 않으므로, 매치 실패 결과가 더 빨리 난다.
yes-regexp
를 매치함
yes-regexp
를 매치함
no-regexp
를 매치함
condition
을 나타내는 여러 가지 형태:
(정수)
\정수
에 해당하는 backreference(259)가 정규식 앞부분에서 매치되었다면 참
(<name>)
또는 ('name')
으로 사용 가능
$x$x
또는 $x$y$y$x
형태의 단어를 찾는 예:
(?...)
- zero-width(261) assertion(262)
(R)
, (R1)
,(R2)
..., (R&name)
(R)
), 재귀적으로 호출될 때 특정 번호로 참조되는 그룹으로부터 실행되었는지 ((R1)
,(R2)
...), 특정 이름으로 참조되는 그룹으로부터 실행되었는지 (R&name)
에 대해 체크
"$x$x"
또는 "$x$y$y$x"
형태의 단어들을 검색한다:
% simple_grep '^(\w+)(\w+)?(?(2)\g2\g1|\g1)$' /usr/dict/words beriberi coco couscous deed ... toot toto tutulookbehind 조건은, 백레퍼런스와 같이 사용되어, 앞에서 매치된 내용이 뒤의 매치에 영향을 주게 한다:
/[ATGC]+(?(?<=AA)G|C)$/;
AAG
로 끝나거나, 그 외의 베이스 쌍 조합과 C
로 끝나는 것을 찾는 예:
(?((?<=AA))G|C)
가 아님에 유의. lookbehind, lookahead, code assertion 의 경우는 조건 바깥쪽에 다시 괄호를 써줄 필요는 없다.
(a)?b(?(1)c|d)
은, 첫번째 그룹 (a)
가 매치되면 b
뒤에 c
가, 그렇지 않으면 d
가 매치된다. 이 때 눈여겨 볼 점은
(a)?
는 스트링의 "a"에 매치되지 않을 경우는 아예 정규식에 관여되지 않고, \1
과 같은 참조는 실패하게 된다. 그런데 만일 이 부분을 (a?)
라고 쓴다면, 이 그룹은 항상 "a" 또는 ""에 매치되며, 항상 정규식에 유효하게 참여한다. 따라서 ?(1)
은 항상 참이 되어 버릴 것이다.
c
가 매치되지 않으므로 실패하지만, 정규식 엔진은 다시 전체 스트링의 그 다음 위치에서부터 매칭을 시도하고, 결과적으로 "abd"의 "bd"부분이 패턴에 매치하게 된다. 이걸 원하지 않는다면 패턴에 앵커를 두어 ^(a)?b(?(1)c|d)$
와 같이 했야 한다.
/^ (?&osg)\ * ( (?&int)(?&dec)? | (?&dec) ) (?: [eE](?&osg)(?&int) )? $ (?(DEFINE) (?<osg>[-+]?) # 생략 가능한 부호 (?<int>\d++) # 정수 (?<dec>\.(?&int)) # 소수부 )/x
/(?: (\w) (?...Here be a palindrome...) \g{-1} | \w? )/x무시해야 될 것들을 제거하기 위해 앞뒤에
\W*
만 붙여주면, 전체 패턴이 완성된다:
my $pp = qr/^(\W* (?: (\w) (?1) \g{-1} | \w? ) \W*)$/ix; for $s ( "saippuakauppias", "A man, a plan, a canal: Panama!" ){ print "'$s' is a palindrome\n" if $s =~ /$pp/; }
(?...)
안에는 백레퍼런스의 절대 번호나 상대 번호 둘 다 쓸 수 있다. 전체 패턴은 (?R)(273) 또는 (?0)(274) 으로 표시할 수 있다. 그룹에 이름을 붙였을 경우 (?&name)(275)으로 그 그룹을 재귀호출할 수 있다.
주인장 보충: 재귀적 정규표현식을 사용하는 예를 찾기가 힘든데, 주로 balanced text, 즉 좌우에 대칭되는 표식에 의해 둘러싸여 있으면서, 또다른 balanced text가 중첩될 수 있는 상황을 풀 수 있는 식을 볼 수 있었다.
- 이 튜토리알에 언급된 회문 예제도 결국 같은 형태
( 3 + ( 2 * 6 ) )
같이 괄호로 둘러싸인 수식<tag1>...<tag2>..</tag2>...</tag1>
처럼 태그로 둘러싸인 텍스트그러나 일반적으로, 심지어 perlfaq 글에서마저, 애초에 이런 형태의 텍스트, 특히 html,xml 등 태그가 포함된 텍스트를 다루는 것은 정규식이 아니라 그 용도로 나온 모듈을 사용하는 게 훨씬 낫다고 하고 있다. 어쨌거나 perlfaq에 있는 예제를 보면, 부등호로 둘러쌓인
- [Perl faq6. Can I use Perl regular expressions to match balanced text?]
- [Crucial Concepts Behind Advanced Regular Expressions]
<텍스트>
부분을 추출한다. 이 때도 역시 중첩되어 있을 수 있다.my $string =<<"HERE"; I have some <brackets in <nested brackets> > and <another group <nested once <nested twice> > > and that's it. HERE my @groups = $string =~ m/ ( # 캡처 버퍼 1의 시작 < # 여는 부등호에 매치 (?: [^<>]++ # 부등호를 제외한 문자들이 반복, 백트래킹하지 않음 | (?1) # < 또는 > 발견, 캡처 버퍼 1을 재귀적으로 부름 )* > # 닫는 부등호에 매치 ) # 캡처 버퍼 1의 끝 /xg; $" = "\n\t"; print "Found:\n\t@groups\n";실행결과:Found: <brackets in <nested brackets> > <another group <nested once <nested twice> > >이제, 위의 "조건부 정규표현식" 절에서 언급된, "조건"을 묘사하는 세번째 패턴을 테스트해보자. (이건 주인장이 만들어본 예제라서, 정확하지 않을 수 있음)
- 위의 회문 매칭과 결국 개념은 똑같다.
- 중첩되지 않은 패턴은,
<
로 시작하고,<
나>
가 아닌 글자가 반복되다가,>
로 끝난다. 패턴으로 나타내면<[^<>]++>
- 중첩된 패턴의 경우는,
<
로 시작하고, 부등호가 아닌 글자 또는 중첩된 패턴(즉 자기 자신과 같은 패턴)이 반복되다가,>
로 끝난다. 따라서 정규식 내부가(?: [^<>]++ | (?1) )*
이 된다.실행 결과:
- 부등호로 둘러싸인 텍스트가 중첩되었을 경우, 가장 바깥쪽 단계의 텍스트를 제외하고, 내부에 중첩된 텍스트는 소문자가 들어가면 안 된다는 조건을 추가
- 아까는
[^<>]++
로 나타냈던 부분을, 조건을 추가해서(?(R) [^a-z<>]++ | [^<>]++ )
로 바꾼다.- 테스트를 위해
$string
값에서 두번째 줄 "nested twice"를 "NESTED TWICE"로 고친다.Found: <nested brackets> <nested once <NESTED TWICE> >R1
이나R&name
형태는, 재귀적으로 호출할 때(?번호)
또는(?&이름)
으로 호출했다면 그 번호 또는 이름이,R
뒤에 있는 번호 또는 이름과 일치할 때 참이 된다. 예를 들어((패턴))
이 형태는 바깥쪽 괄호나 안쪽 괄호 어느 쪽을 재귀호출해도 결국 똑같이 매칭이 되긴 하지만, 호출을(?2)
로 했는데 조건검사를(?(R1)..)
으로 하면 이건 거짓으로 판정된다. 또한, 이름으로 호출하고 번호로 검사하거나 그 반대로 하는 것은 허용되는 걸로 보인다.
code
를 정규표현식의 일부로 사용
$^R
에 저장됨. 이 변수를 이후에 정규표현식 안에서 사용 가능
$x = "abcdef"; $x =~ /abc(?{print "Hi Mom!";})def/; # 매치됨, # 'Hi Mom!'출력 $x =~ /aaa(?{print "Hi Mom!";})def/; # 매치되지 않음, # 'Hi Mom!' 출력않음다음 두 예는 주의:
$x =~ /abc(?{print "Hi Mom!";})ddd/; # doesn't match, # no 'Hi Mom!' # but why not? $x =~ /abc(?{print "Hi Mom!";})[dD]dd/; # doesn't match, # but _does_ print
$x =~ /(?{print "Hi Mom!";})/; # matches, # prints 'Hi Mom!' $x =~ /(?{$c = 1;})(?{print "$c";})/; # matches, # prints '1' $x =~ /(?{$c = 1;})(?{print "$^R";})/; # matches, # prints '1'정규표현식이 코드 표현식이 있는 부분을 백트래킹하게 되고, 그 코드 표현식 안에 사용된 변수가
local
키워드를 사용하여 지역화되어 있다면, 코드 표현식에 의하여 변수값이 바뀌었던 것도 취소된다.
$x = "aaaa"; $count = 0; # initialize 'a' count $c = "bob"; # test if $c gets clobbered $x =~ /(?{local $c = 0;}) # initialize count ( a # match 'a' (?{local $c = $c + 1;}) # increment count )* # do this any number of times, aa # but match 'aa' at the end (?{$count = $c;}) # copy local $c var into $count /x; print "'a' count is $count, \$c variable is '$c'\n";
'a' count is 2, $c variable is 'bob'
(?{local $c = $c + 1;})
대신 (?{$c = $c + 1;})
라고 쓸 경우는 백트래킹할 때 변경이 취소되지 않는다:
'a' count is 4, $c variable is 'bob'취소될 수 있는 건 지역화된 변수의 값 변화 뿐이며, 코드 표현식에 의한 다른 부효과는 영구히 남게 된다:
$x = "aaaa"; $x =~ /(a(?{print "Yow\n";}))*aa/;
Yow Yow Yow Yow
$^R
은 자동으로 지역화되며, 백트래킹이 이뤄질 때도 올바르게 동작한다.
코드 표현식을 조건으로 사용하여 영어와 독어의 정관사를 매치하는 예:
$lang = 'DE'; # use German ... $text = "das"; print "matched\n" if $text =~ /(?(?{ $lang eq 'EN'; # is the language English? }) the | # if so, then match 'the' (der|die|das) # else, match 'der|die|das' ) /xi;
(?((?{...}))yes-regexp|no-regexp)
로 표기할 필요는 없다.
$bar = 5; $pat = '(?{ 1 })'; /foo(?{ $bar })bar/; # compiles ok, $bar not interpolated /foo(?{ 1 })$bar/; # compile error! /foo${pat}bar/; # compile error! $pat = qr/(?{ $foo = 1 })/; # precompile code regexp /foo${pat}bar/; # compiles ok
$regexp = <>; # read user-supplied regexp $chomp $regexp; # get rid of possible newline $text =~ /$regexp/; # search $text for the $regexp
$regexp
에 코드 표현식이 들어갈 경우 사용자는 임의의 Perl 코드를 실행 가능하다. (system('rm -rf *')
와 같은)
use re 'eval'
을 실행하여야 한다:
use re 'eval'; # throw caution out the door $bar = 5; $pat = '(?{ 1 })'; /foo(?{ 1 })$bar/; # compiles ok /foo${pat}bar/; # compiles okpattern code expression(280) (??{code})(281)
$length = 5; $char = 'a'; $x = 'aaaaabb'; $x =~ /(??{$char x $length})/x; # matches, there are 5 of 'a'마지막 예문:
1101010010001...
에서 1
의 간격이 피보나치 수열 0,1,1,2,3,5...의 형태로 되어 있는지를 검사하는 코드:
$x = "1101010010001000001"; $z0 = ''; $z1 = '0'; # initial conditions print "It is a Fibonacci sequence\n" if $x =~ /^1 # match an initial '1' (?: ((??{ $z0 })) # match some '0' 1 # and then a '1' (?{ $z0 = $z1; $z1 .= $^N; }) )+ # repeat as needed $ # that is all there is /x; printf "Largest sequence matched was %d\n", length($z1)-length($z0);
$^N
은 마지막 캡처 그룹에 일치된 내용으로 설정된다는 걸 기억하라.
It is a Fibonacci sequence Largest sequence matched was 5변수
$z0
과 $z1
은 코드 표현식 바깥쪽에 있는 보통의 변수들과 달리, 정규식이 컴파일될 때 치환되지 않는다. 대신 Perl 이 매치되는 것을 찾아 검색하는 동안 코드 표현식을 만나게 되면 그 때 평가된다.
//x(282)를 쓰지 않고 위 정규식을 쓰면 다음과 같다.
/^1(?:((??{ $z0 }))1(?{ $z0 = $z1; $z1 .= $^N; }))+$/
//x
를 써서 확장 표현식을 사용해야 표현식을 작성하고 디버깅하는데 용이하다.
(*F)
로 줄여 쓸 수 있음
%count = (); "supercalifragilisticexpialidoceous" =~ /([aeiou])(?{ $count{$1}++; })(*FAIL)/i; printf "%3d '%s'\n", $count{$_}, $_ for (sort keys %count);저 패턴은 일부 문자들에 매치되는 클래스로 시작된다. 여기에 매치되면,
$count{'a'}++
와 같은 구문이 실행되어 매치된 글자의 카운터를 증가시킨다. 그 다음 (*FAIL)
이 말 그대로 매칭을 실패하게 만들고, 정규식 엔진은 지금껏 배운 대로 스트링이 끝나기 전까지 계속 포지션을 이동시키며 다음 모음으로 이동한다. 따라서, 매치되든 되지 않든 상관없이 정규식 엔진은 전체 스트링을 다 검사할 때까지 계속 진행한다.
위 방법이 다음과 같은 다른 해결책에 비해 눈에 띄게 빠르다는 것은 주목할 만 하다12:
$count{lc($_)}++ for split('', "supercalifragilisticexpialidoceous"); printf "%3d '%s'\n", $count2{$_}, $_ for ( qw{ a e i o u } );
use re 'eval'
use re 'taint'
use re 'taint'; $tainted = <>; @parts = ($tainted =~ /(\w+)\s+(\w+)/; # 이제 @parts도 오염되었음
taint
를 사용하라.
taint
와 eval
프라그마는 렉시컬 스코프를 따른다. 즉 프라그마를 둘러싼 블록 안에서만 효과가 있다.
re '/flags'
use re '/m'; # 또는 다른 어떤 플래그라도 $multiline_string =~ /^foo/; # /m 이 묵시적으로 적용된다
re 'debug'
re 'debugcolor'
- termcap 컬러를 출력할 수 있는 터미널에서는 컬러로 출력함
% perl -e 'use re "debug"; "abc" =~ /a*b+c/;'
1 Compiling REx 'a*b+c' 2 size 9 first at 1 3 1: STAR(4) 4 2: EXACT <a>(0) 5 4: PLUS(7) 6 5: EXACT <b>(0) 7 7: EXACT <c>(9) 8 9: END(0)
STAR(4)
- 오브젝트(여기서는 'a')에 별표가 붙은 형태이며, 매치할 경우 4번 라인의 PLUS(7)
로 가라는 의미
1 floating 'bc' at 0..2147483647 (checking floating) minlen 2 2 Guessing start of match, REx 'a*b+c' against 'abc'... 3 Found floating substr 'bc' at offset 1... 4 Guessed: match at offset 0실제 매칭 연산이 이뤄지는 과정:
1 Matching REx 'a*b+c' against 'abc' 2 Setting an EVAL scope, savestack=3 3 0 <> <abc> | 1: STAR 4 EXACT <a> can match 1 times out of 32767... 5 Setting an EVAL scope, savestack=3 6 1 <a> <bc> | 4: PLUS 7 EXACT <b> can match 1 times out of 32767... 8 Setting an EVAL scope, savestack=3 9 2 <ab> <c> | 7: EXACT <c> 10 3 <abc> <> | 9: END 11 Match successful! 12 Freeing REx: 'a*b+c'
n <x> <y>
형태
<x>
- 일치한 스트링
<y>
- 아직 매치 검사가 수행되지 않은 부분
| 1: STAR
- 현재 컴파일 리스트(위에서 본)의 1번 라인에 있음
print
구문을 삽입:
"that this" =~ m@(?{print "Start at position ", pos, "\n";}) t(?{print "t1\n";}) h(?{print "h1\n";}) i(?{print "i1\n";}) s(?{print "s1\n";}) | t(?{print "t2\n";}) h(?{print "h2\n";}) a(?{print "a2\n";}) t(?{print "t2\n";}) (?{print "Done at position ", pos, "\n";}) @x;
Start at position 0 t1 h1 t2 h2 a2 t2 Done at position 4
m//
과 s///
연산자에 관해서 - perlop 의 "Regexp Quote-Like Operators" 섹션[3]
# 간단한 파서 my $line = "Just another regex hacker, Perl hacker, and that's it!\n"; while( 1 ) { my( $found, $type )= do { if( $line =~ /\G([a-z]+(?:'[ts])?)/igc ) { ( $1, "a word" ) } elsif( $line =~ /\G (\n) /xgc ) { ( $1, "newline char" ) } elsif( $line =~ /\G (\s+) /xgc ) { ( $1, "whitespace" ) } elsif( $line =~ /\G ( [[:punct:]] ) /xgc ) { ( $1, "punctuation char" ) } else { last; () } }; print "Found a $type [$found]\n"; }
$_ = "Here come Wilma and Fred!"; print "Matches" if /Fred.*Wilma|Wilma.*Fred/; # alternation을 사용한 하나의 정규표현식 print "Matches" if /Fred/ && /Wilma/; # 두개의 정규표현식을 사용한 것이 위의 표현보다 더 간단하다. print "Matches" if /(?=.*Wilma).*Fred/; # positive lookahead assertion 을 사용한 하나의 정규표현식
# 잘못된 경우 print "Matches" if /(?Wilma).*Fred/; # 이것은 Wilma가 Fred보다 앞에 있는 경우에만 매치된다.zero-width(294)특성을 이용하여 split 함수에서 사용하는 예:
my @words = split /(?=[A-Z])/, 'CamelCaseString'; # "C", "C", "S"가 없어지지 않는다. print join '_', map { lc } @words; # camel_case_string
my $pattern = "foo"; my $qr = qr/foo/; # 아래 네 가지는 항상 같은 결과 $str =~ /$pattern/; # 흔히 보는 예 $str =~ $pattern; # 희한하게 생겼지만 이것도 잘 동작한다 $str =~ $qr; $str =~ /$qr/; # 이 둘도 동치단순 문자열 패턴 뿐 아니라 캐릭터 클래스나 괄호나 기타 등등도 그대로 동일하게 적용된다.
my $str = "my name is hong"; my $pattern = 'name is (\w+)$'; my $qr = qr/name is (\w+)$/; if ( $str =~ $pattern ) { print "[$1]\n"; } # hong if ( $str =~ $qr ) { print "[$1]\n"; } # 이것도 hongmodifier(296) 사용도 마찬가지. 표현만 달라지지 똑같은 효과를 낼 수 있다:
my $str = "my NAME is hong"; # NAME 이 대문자가 되었음 my $pattern = '(?i)name is (\w+)$'; # 확장 패턴 사용 my $qr = qr/name is (\w+)$/i; # modifier 사용 if ( $str =~ $pattern ) { print "[$1]\n"; } if ( $str =~ $qr ) { print "[$1]\n"; } # 둘 다 hong 검출요컨데 딱히 qr//을 써야만 매칭을 할 수 있고 스트링 스칼라로는 할 수 없는 경우가 따로 있는 것 같지는 않다. (주인장의 추정일 뿐이긴 하지만) qr//의 장점은 perldoc 에서 언급했듯이 "미리 컴파일하여 저장"하고 "사용할 때는 컴파일하지 않는다"라는 점이다. 이것이 어떤 의미인지는 직접 코드를 확인해보자:
#!/usr/bin/perl use re 'debug'; # Perl 내부에서 정규표현식을 처리하는 과정을 STDERR로 출력함 local $| =1; my $str = "iname"; ################# # qr//을 사용하는 예 ################# my @reg_qr = ( qr/a/, qr/b/, qr/c/ ); # 이 시점에서 세 개의 정규표현식이 컴파일된다. # 이하의 내용에서 print 문은 단지 각 구문의 실행을 추적하기 위해 넣었음 for my $c ( 10 .. 11 ) { print "\n\n-- $c --------------------\n\n"; for ( 0 .. 2 ) { print "------------------------------\n"; my $reg = $reg_qr[$_]; if ( $str =~ $reg ) { # 여기서는 컴파일하지 않고 바로 사용한다 print "MATCH!!!!!!!!!!\n"; } else { print "NOT MATCH~~~~~~\n"; } } } print "\n\n\n", "="x30, "\n\n\n"; ################# # 스트링 스칼라 변수를 사용하는 예 ################# my @reg_str = ( "a", "b", "c" ); for my $c ( 10 .. 11 ) { print "\n\n-- $c --------------------\n\n"; for ( 0 .. 2 ) { print "------------------------------\n"; my $reg = $reg_str[$_]; if ( $str =~ $reg ) { # =~ 연산을 할 때마다 컴파일한다 print "MATCH!!!!!!!!!!\n"; } else { print "NOT MATCH~~~~~~\n"; } } }보다시피, 두 번의 for 루프는 각각 패턴 "a", "b", "c" 를 각각 비교하는 과정을 다시 두 번 반복한다. 실행결과는 다음과 같다: 결과에서 보면 qr을 사용한 테스트에서는 세 개의 패턴을 한번씩만 컴파일한 후에, 두번째 루프를 돌 때는 컴파일 없이 바로 사용하고 있다. 그러나 스칼라 변수를 사용한 테스트에서는 변수의 값이 매번 바뀔 때마다 다시 컴파일을 하기 때문에 총 여섯 번 컴파일한다. Benchmark 를 사용하여 성능을 비교해보면 (위 코드에서 print 문을 전부 제거한 후 비교하였음) 속도가 두 배 이상 차이난다.
Rate scalar qr scalar 42309/s -- -57% qr 97303/s 130% --추가로, 만일 스칼라 변수를 사용한 곳에서 //o(297) modifier를 사용하여 강제로 재컴파일을 금지시키면 어떻게 될까?
my $reg = $reg_str[$_]; if ( $str =~ /$reg/o ) { # /o 사용 }이 경우는 디버그 메시지를 가지고 확인해보면, 여섯 번의 비교 중에 제일 첫번째 비교를 할 때 컴파일을 한 후 나머지 다섯번의 비교에서는 컴파일을 하지 않는 것을 볼 수 있다. 속도도 따라서 qr 보다 1.5배 정도 빠르게 나온다. 그러나 여섯번 모두 "a" 패턴을 가지고 비교를 하므로, 잘못된 실행 결과가 나온다 (여섯번 모두 매치하는 걸로 판정됨)
aero@doc:~$ perl -MDevel::Peek -e '$s="foo";Dump($s)' SV = PV(0x8cd9700) at 0x8cf9e38 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x8cf5f28 "foo"\0 CUR = 3 LEN = 4
aero@doc:~$ perl -MDevel::Peek -e '$s=qr/foo/;Dump($s)' SV = IV(0x8776e3c) at 0x8776e40 REFCNT = 1 FLAGS = (ROK) RV = 0x8759520 SV = REGEXP(0x87844a0) at 0x8759520 REFCNT = 1 FLAGS = (OBJECT,POK,FAKE,pPOK) IV = 0 PV = 0x877a548 "(?-xism:foo)" CUR = 12 LEN = 0 STASH = 0x8758fe0 "Regexp"qr은 컴파일된 정규식 Regexp객체임을 알 수 있다. 정규식 매칭의 표현의 코드 해석
aero@doc:~$ perl -MO=Deparse -e '$p="foo bar";$s="foo";$p=~$s' $p = 'foo bar'; $s = 'foo'; $p =~ /$s/; -e syntax OK
aero@doc:~$ perl -MO=Deparse -e '$p="foo bar";$s=qr/foo/;$p=~$s' $p = 'foo bar'; $s = qr/foo/; $p =~ /$s/; -e syntax OK정규식 매칭 표현구문에서 구분자가 생략되어도 Perl은 알아서 넣어서 해석한다. 마지막 예제는 컴파일된 정규식 같은경우는 $reg에 넣으면 그 자체가 컴파일된 정규식 객체를 가르키게되어서 그대로 사용가능하지만 그냥 스칼라 스트링을 $reg에 넣으면 설령 그것이 정규표현식 구문에서 컴파일 되었다고 해도 $reg는 어떤 객체를 가르키고 있는 레퍼런스가 아니라 복사된 스칼라값일 뿐이므로 컴파일된 정규식이 원래값이 있는 곳을 찾아 컴파일된 정규식으로 교체할 수 없기 때문에 결과는 당연해 보입니다. o modifier는 이제 deprecated된 feature로 쓰지 않아도 Perl이 필요하다면 자동적으로 최적화 시키고, 어떤 변화된 값이 오는 곳에 o modifier를 쓰는 건 예상치 못한 side effect를 가져온다고 이미 조심을 해야된다고 알려진터라 실제에는 그렇게 사용할 일도 없을 것 같고요. qr의 유용한 점은 마지막 예에서 처럼 여러 set들의 정규식이 반복적으로 사용되어져야 할때( 예: http://www.effectiveperlprogramming.com/blog/183 )유용하겠죠 :)
'My cat is Buster Bean' =~ m/Buster/; print "I matched $&\n"; # 여기서 매치 변수를 사용해버렸기 때문에 while (<>) { next unless /Bean/; # 매치할 때마다 매번 오버헤드가 발생 }따라서:
use English;
로 모듈을 로드하는 순간 세 가지 매치 변수에 해당하는 영문 이름 변수가 로드가 되며, 따라서 매치 변수를 이후 사용하지 않아도 이미 성능 하락이 발생한다.
use English qw(-no_match_vars)
를 하여 매치 변수를 쓰지 않을 것을 명시하라
use 5.010; 'My cat is Buster Bean' =~ m/\s\w+\sBean/p; # /p 옵션 사용 say "I matched ${^MATCH}"; while (<>) { next unless /Bean/; # 오버헤드 없음 }5.10.0(311) 이전 버전에서는, 정규식 자체를 수정하여 명시적으로 ( )(312)를 사용하여 캡처링하라:
_____사용하지 말 것_____ | _____5.10 이전 버전에서는_____ | _____5.10 이하 버전에서는_____ |
/pattern/ 이후 $` | /(.*?)pattern/ 이후 $1 | /pattern/p 이후 ${^PREMATCH} |
/pattern/ 이후 $& | /(pattern)/ 이후 $1 | /pattern/p 이후 ${^MATCH} |
/pattern/ 이후 $' | /pattern(.*)/ 이후 $+ | /pattern/p 이후 ${^POSTMATCH} |
my $str = qq|aaa "bbb" ccc "ddd" eee|; # greedy 수량자 /+/ if ( $str =~ /"(.+)"/ ) { print "[$1]\n"; } # 출력은 당연히 [bbb" ccc "ddd] # non-greedy 수량자 /+?/ if ( $str =~ /"(.+?)"/ ) { print "[$1]\n"; } # 출력은 [bbb] # greedy 수량자 /+/ if ( $str =~ /"(.+)" eee/ ) { print "[$1]\n"; } # 역시 당연히 [bbb" ccc "ddd] # non-greedy 수량자 /+?/ if ( $str =~ /"(.+?)" eee/ ) { print "[$1]\n"; } # [ddd]가 아니라, [bbb" ccc "ddd]이다 # 이 경우는 . 대신 [^"]를 써야 한다. # greedy 수량자 /+/ if ( $str =~ /"([^"]+)" eee/ ) { print "[$1]\n"; } # non-greedy 수량자 /+?/ if ( $str =~ /"([^"]+?)" eee/ ) { print "[$1]\n"; } # 위 둘 다 결과는 [ddd]non-greedy 수량자를 쓰는 경우라도, 일단 첫번째 원칙은 스트링의 가장 왼쪽에서부터 매치를 하는 것이므로,
"bbb" c
가 /"(.+?)" eee/
와 매치되지 않는 게 확인된 시점에서, 그 다음은 .+?
의 범위를 늘려나가며 재시도를 하게 된다.
my $str = "a1a2a3a4a5"; # a<숫자> 형태의 문자열을 전부 찾아내어 어떤 처리를 하고 싶다 while ( $str =~ /(a\d)/ ) { print "[$1]\n"; # 어떤 처리 : 출력 }
[a1] [a1] ... 무한 루프위 코드는 매번 $str의 시작 부분부터 검사를 하기 때문에 "a1"만 찾으며 무한 루프를 돈다. 코드2:
my $str = "a1a2a3a4a5"; while ( $str =~ /(a\d)/g ) { # /g modifier print "[$1] at position ", pos($str), "\n"; }
[a1] at position 2 [a2] at position 4 [a3] at position 6 [a4] at position 8 [a5] at position 10이런 경우에 가장 흔하게 사용하는 패턴이다. 코드3:
my $str = "a1a2a3a4a5"; while ( $str =~ /(a\d)/gc ) { print "[$1] at position ", pos($str), "\n"; } # /c 때문에 $str의 포지션은 여전히 10이고, 따라서 아래 루프의 매치는 실패 while ( $str =~ /(a\d)/g ) { print "Again, [$1] at position ", pos($str), "\n"; }/c 변경자가 없었다면 두번째 루프에서 다시 "a1"부터 출력되었을 것이다. 그러나 /c 변경자를 첫번째 루프에서 사용했기 때문에, "a5"를 찾은 후 그 다음 매치가 실패했을 때 $str의 포지션 정보가 리셋되지 않은 채로 남아 있고, 두번째 루프에서 그 지점(오프셋 10)에서 매치를 시작하기 때문에 곧바로 실패하여 루프를 빠져나온다.
[a1] at position 2 [a2] at position 4 [a3] at position 6 [a4] at position 8 [a5] at position 10코드4: 발견한 문자열이 "a2"인 경우에 한해서, 그 바로 뒤에 "a3"이 따라붙으면 이 "a3"은 다음 번 검사에서 매치시키지 않고 스킵하고 싶다고 하자. 언제나 "a3"은 처리하지 않겠다면 애초에 정규식을
a[012456789]
로 만들거나, 루프 안에서 if로 $1 eq 'a3'
인 경우를 따로 처리할 수 있지만, 지금과 같이 <바로 앞에 "a2"가 있었던 경우에만>라는 조건이 붙으면 복잡해진다. 직전에 발견되었던 게 "a2"인지 여부를 저장하는 변수를 추가로 써야 하거나...
이런 경우 /g 변경자를 써서 포지션을 넘겨 버릴 수 있다.
# 이 코드는 불완전 my $str = "a1a2a3a4a5"; while ( $str =~ /(a\d)/g ) { print "[$1] at position ", pos($str), "\n"; if ( $1 eq "a2" ) { # a3 을 매치시켜서 포지션 이동 $str =~ /a3/g; } }
[a1] at position 2 [a2] at position 4 [a4] at position 8 [a5] at position 10언뜻 보면 성공한 것 같지만, 이 코드는 문제가 있다. 먼저, 만일 "a2" 뒤에 "a3"이 없다면? if 블록 안의 정규식 검사가 매치에 실패하기 때문에 포지션이 리셋되고, 다음 검사는 다시 문자열의 처음부터 검사하게 된다.
my $str = "a1a2a!!a4a5"; # a2 뒤에 a3이 없다
[a1] at position 2 [a2] at position 4 [a1] at position 2 [a2] at position 4 ... 무한 루프따라서, "a3"을 찾는 검사에서 실패하더라도 포지션을 리셋하지 않도록 해야 한다.
if ( $1 eq "a2" ) { # /c - a3 매치에 실패하더라도 포지션을 리셋하지 않음 $str =~ /a3/gc; }이제 무한 루프는 해결했지만, 여전히 문제가 남아 있다. 이 코드는 "a2"를 발견한 시점에서 그 다음 나타나는 첫번째 "a3"까지 검사를 진행하기 때문에, "a2"와 "a3" 사이에 다른 패턴이 들어가 있으면 그걸 전부 건너뛰어 버릴 것이다.
my $str = "a1a2a9a3a4a5"; # a2와 a3 사이에 a9가 끼어 있다.
[a1] at position 2 [a2] at position 4 [a4] at position 10 <-- a9 까지 스킵해버린다. [a5] at position 12따라서 현재 포지션 바로 직후에 있는 "a3"만 찾기 위해 앵커가 필요하고,
^
는 답이 아니다. 이럴 때 \G(314)를 사용할 수 있다.
코드5:
my $str = "a1a2a9a3a4a5"; while ( $str =~ /(a\d)/g ) { print "[$1] at position ", pos($str), "\n"; if ( $1 eq "a2" ) { # a3 을 매치시켜서 포지션 이동 # /c - a3 매치에 실패하더라도 포지션을 리셋하지 않음 # \G - a2 매치에 성공한 그 지점을 나타내는 앵커 $str =~ /\Ga3/gc; } }
[a1] at position 2 [a2] at position 4 [a9] at position 6 [a3] at position 8 [a4] at position 10 [a5] at position 12어떻게든 정규식 패턴만으로 동일한 동작을 하게 하려면... 아래에 있는 코드는 주인장이 떠올린 몇 가지 패턴들이고, 테스트 케이스에 대해서는 다 잘 동작하지만... 어떤 버그가 숨겨져 있을지도. 코드9:
foreach my $str ( "a1a2a3a4a5", "a1a2!!a4a5", # a2 뒤에 a3이 없는 경우 "a1a2a9a3a4a5", # a2 와 a3 사이에 다른 매치가 있는 경우 "a1a3a4a5", # a2가 없는 경우 ) { print "---------- $str ----------\n"; # code_05 에서 사용한 /c, \G print " 1. using /c, \\G\n"; while ( $str =~ /(a\d)/g ) { print "[$1] at position ", pos($str), "\n"; if ( $1 eq "a2" ) { $str =~ /\Ga3/gc; } } # 백레퍼런스에 이름을 붙여 사용 # a2a3 이 매치되면 그 중 a2에, # 그 외의 경우는 a<숫자>에 PAT 백레퍼런스가 생긴다 print " 2. named backreference\n"; while ( $str =~ /(?<PAT>a2)a3|(?<PAT>a\d)/g ) { print "[$+{PAT}] at position ", pos($str), "\n"; } # 또는 # 캡처그룹 번호 리셋 (?| ... ) print " 3. alternative capture group numbering\n"; # 그룹번호: $1 $1 while ( $str =~ /(?|(a2)a3|(a\d))/g ) { print "[$1] at position ", pos($str), "\n"; } # 또는 # 바로 앞에 a2가 있지 않은(부정적 룩비하인드) a3, 또는 a<3이 아닌 숫자> print " 3. lookbehind\n"; while ( $str =~ /((?<!a2)a3|(?:a[012456789]))/g ) { print "[$1] at position ", pos($str), "\n"; } }
s/\.(?=.*\.)/ /g
- 마침표를 "\."로 표기했기 때문에 좀 복잡해보이지만, s/A(?=.*A)/ /g
형태로 보면, "A가 있고, 그 뒤를 이어서 임의의 문자가 있고 그 이후에 A가 있는 경우"가 매치되는 것이므로, 결과적으로 "마지막 A가 아닌 나머지 A"들이 줄줄이 매치되면서 치환된다.
perlretut_5_*_*.pod
파일을 찾은 후, text 형태로 출력한 후 diff 를 보거나 vim 등에서 두 파일을 diff 모드로 띄워두는 게 무난한 듯
perldoc -otext perlretut_5_8_8.pod
//o
modifier를 사용하여 한번만 컴파일하도록 지시했었다. 튜토리알에 포함하기에는 좀 생뚱맞은 문구 같음. 기존 버전에 익숙한 사람들을 위해서 문서 후반에 따로 정리하는게 나았을 듯eval {...}
로 둘러싼 후 실행하여 결과를 가지고 치환환다고 설명되었다가, 5.14에서 바뀌었음/usr/lib/perl5/5.8.8/unicore/NamesList.txt
에, 스트로베리 펄 5.10.0에서는 C:\strawberry\perl\lib\unicore\NamesList.txt
에 있었음\C
를 사용한다. \C
는 .
와 유사하나, 0-255 사이의 어떤 바이트에도 매치된다는 게 다르다.\C
에 대한 언급이 유니코드 얘기할 때 나온다. \C
는 유니코드 스트링을 대상으로 매칭할 때 한 "바이트"에 매치되는 캐릭터 클래스이다. 5.14버전에서는 그 언급이 사라졌는데 여기에는 삭제되지 않았다$_ 5, 174 | =~ 3, 71, 151, 173 !~ 4, 152 | anchor 10, 238 $ 14, 56, 134 \A 59 \B 49 \b 48, 240 \G 167, 254, 292, 314 \Z 60 \z 62 ^ 12, 55, 239 | assertion 242, 262 |
backreference 76, 259 (?<name>) 85 (?'name') 86 \g1 77 \g{-1} 82 \g{name} 87 named backreference 84, 260 relative backreference 81 | backtracking control (*FAIL) 284 | capture group number reset (?|...) 90 | character class 17, 19, 206 $ 24 - 20, 25 . 37, 54 [:name:] 215 \ 22 \C 251 \c 190 \D 34, 220 \d 31, 216 \E 189, 192 \L 187 \l 185 \N 40 \N{name} 200 \P 210 \p 209 \p{name:value} 212 \p{name=value} 211 \P{name} 208 \p{name} 207 \Q 191 \S 35 \s 32, 217 \U 188 \u 186 \W 36 \w 33, 218 \X 213 ] 21 ^ 23, 26 POSIX-style 214 |
code evaluation 265, 277, 287 (??{code}) 281 (?{code}) 276 pattern code expression 280 | conditional expression 256, 279, 288 (?(condition)yes-regexp) 257 (?(condition)yes-regexp|no-regexp) 258 | context list context 73, 165, 181 scalar context 72, 162, 182 | definition group (?&name) 269 (?(DEFINE)(?<name>pattern)...) 268 |
Escape Sequences 9, 199 | extended pattern 110, 222 (?#text) 224 (?^...:) 236 (?i) 226 (?m) 228 (?s) 230 (?x) 232 embedded comment 223 | independent subexpression 289 (?>regexp) 252 | lookahead 243, 263, 293, 315 (?!regexp) 249 (?<!fixed-regexp) 250 (?<=fixed-regexp) 246 (?=regexp) 244 lookbehind 245, 264 |
matching operator 148 /regexp/ 2, 149 m!regexp! 6, 150 m'regexp' 158 | matching postion $+[n] 95 $-[n] 94 @+ 93 @- 92 | matching variable 69, 106, 175 $& 97, 299 $' 98, 300 $+ 74 $1 70, 248, 302 $^N 75 $` 96, 298 ${^MATCH} 101, 308 ${^POSTMATCH} 102, 309 ${^PREMATCH} 100, 307 %+ 88 성능 문제 301 | metacharacter 8, 11, 64, 112 ( ) 67, 68, 312 alternation 63, 109, 123, 145 grouping 66, 108, 184, 303 Word anchor 47 | 65 |
modifier 53, 147, 153, 296 //a 30, 45, 219 //c 161, 164, 291, 313 //d 170 //g 160, 166, 168, 253, 290 //i 18, 156, 227 //l 171 //m 52, 57, 155, 229 //o 169, 297 //p 103, 234, 310 //s 39, 42, 51, 154, 231 //u 203 //x 146, 157, 225, 233, 282 s///e 178 s///g 176 s///r 177, 317 | new line \n 38, 41, 50, 61 | non-capturing 104, 235, 247 (?:regexp) 105, 304 | Perl 5.10.0 27, 79, 80, 83, 89, 99, 137, 267, 270, 283, 306, 311 5.12.0 43 5.14.0 29, 44, 78, 91, 196, 202, 237, 286, 316 5.14.1 1 5.5.0 305 5.6.0 193, 198, 201 |
pos() 163 | pragma 204, 285 | qr// 221, 295 | quantifier 111, 124, 135, 255 * 114 *+ 142 *? 129 + 115 ++ 143 +? 130 ? 113 ?+ 140 ?? 128 greedy 120 maximal match 119 minimal match 125 non-greedy 126 possessive 138 {n,m} 116 {n,m}+ 139 {n,m}? 131 {n,} 117 {n,}+ 141 {n,}? 132 {n} 118 {n}+ 144 {n}? 133 |
recursive pattern 266, 271 (?&name) 275 (?0) 274 (?group-ref) 272 (?R) 273 | s/// 172, 180 s''' 179 | split 107, 183 | Unicode 28, 46, 194, 205 \o{oct} 197 \x{hex} 195 |
zero-width 241, 261, 278, 294 | 스트링 7, 13, 15, 16, 58, 121, 122, 127, 136, 159 |
테이블앞에 붙은 버전을 변수로 받기위해 &1\_JIBUN_CODE 이런식으로 변수뒤에 백슬래쉬가 붙었는데
스크립트 중간중간에 정규식쓰면서 백슬래쉬를 여기저기에 사용한게 많더라고요..
그래서 정규식에 쓰인 것까지 Escape 해버려서 결과값이 다르게 나오는것 같아요
전체스크립트 상단에 SET Escape '\' 설정되어있고 중간에 이런 replace문들이 있는거죠
SELECT
DISTINCT AS CODE, AS ITEMNAME,
TRIM(ADM_EMD) AS NAME1,
REGEXP_REPLACE(ADM_EMD, '([^0-9,.]*)([^동]*)(동|읍|면)', '\1') AS NAME2
FROM &1\_JIBUN_CODE
WHERE
USE_FLAG IN ('1', '2') AND SUBSTR(ADM_CODE,6,10) <> '00000' AND
LENGTH(REGEXP_REPLACE(ADM_EMD, '([^0-9,.]*)([^동]*)(동|읍|면)', '\1'))> 1
그냥 set escape off 할수도없고..저 replace 문들도 사용해야하고..좋은 방법은 없나요.. ㅜ
시도1) set escape 쓸때 백슬래쉬말고 다른기호를 쓴다 => #로 바꿔보니 에러나더라구요
시도2) regexp_replace 쓸때 백슬래쉬말고 다른표현을 쓴다 => 이건 어떻게 해야 동일하게 나올지 잘안되구,자칫 잘못꼬이면 큰일나구,
-- 정규식 검색하다가 들러서 질문남깁니다.. 근데 여기에 질문해도 되는건가요..
오라클 쪽인가본데,
1) 직관적으로 생각해서 백슬래시가 이스케이프 접두사로 쓰이는 상황이라면, 백슬래시 자체를 나타내기 위해서는 \\를 쓰겠지요. 그러니 저 regexp_replace 쪽에서 '\1'이라고 쓴 걸 '\\1' 로 바꿔서 해볼 법 하고요. (그럼 \\가 먼저 \로 바뀌고, 그 상태에서 함수 인자로 들어가 동작하여 성공...하는 게 이론적인 희망)
2) [이 댓글]을 보면 저 시도1에서 말씀하신 것처럼 이스케이프 접두어를 #으로 바꾸는 게 가능해보이는데요. 에러가 난 이유는 다른 데 있었던 게 아닐까요.
"keeper" =~ /^keep$/; # 매치됨
^와$를 사용하면 스트링 전체를 할 수 있다고 해서 위와 같이 매칭이 된다고 되어 있는데 매칭이 되지 않음이 맞지 않을까 합니다.