kpw2012 조금 깊이 들여다보는 정규표현식

155
조금 깊이 들여다보는 qr/정규표현식/ Korean Perl Workshop 2012 2012. 10. 20. 박근영 @gypark [email protected] http://gypark.pe.kr/wiki/Perl

Upload: raymundo

Post on 11-Nov-2014

3.011 views

Category:

Technology


6 download

DESCRIPTION

Korean Perl Workshop 2012 에서 발표한 내용입니다.

TRANSCRIPT

조금 깊이 들여다보는

qr/정규표현식/

Korean Perl Workshop 2012

2012. 10. 20.

박근영

@gypark [email protected]

http://gypark.pe.kr/wiki/Perl

목 차

• 흔히 겪는 오류와 실수

• Perl 5.10 이후에 도입된 정규식 문법

• 자잘한 팁들

Korean Perl Workshop 2012 2

이 문서의 내용과 코드는 주로…

• perlretut (regular expression tutorial) – 번역: http://gypark.pe.kr/wiki/Perl/정규표현식

• perlre

• 손에 잡히는 정규표현식

– 벤 포터, 김경수 번역, 인사이트

• 한 권으로 끝내는 정규표현식

– 잰 고이바에르츠 외, 김지원 번역, 한빛미디어

• WWW …등에서 발췌

Korean Perl Workshop 2012 3

흔히 겪는 오류와 실수

"어째서 일치하지 않을까요?"

"어째서 여기에 일치해 버릴까요?"

Korean Perl Workshop 2012 4

정규식의 어려움

• 일치해야 될 문자열에 일치하는 정규식을 만드는 것은 비교적 쉽다

Korean Perl Workshop 2012 5

• 일치해야 될 문자열에 일치하는 정규식을 만드는 것은 비교적 쉽다

• 일치하지 말아야 할 문자열에 일치하지 않는 정규식을 만드는 것이 어렵다

Korean Perl Workshop 2012 6

• 일치해야 될 문자열에 일치하는 정규식을 만드는 것은 비교적 쉽다

• 일치하지 말아야 할 문자열에 일치하지 않는 정규식을 만드는 것이 어렵다

– 경우의 수가 무한함

– 테스트하기 힘듦

– 상황에 따라 적절한 타협이 필요

Korean Perl Workshop 2012 7

문자열의 앞에서부터 일치

• 정규표현식 일치 검사의 첫번째 원칙

“문자열에서 가능한 한

가장 앞부분에서 일치시킨다”

Korean Perl Workshop 2012 8

• 간단한 예 "cats and dogs" =~ / dog | cat | bird /x;

Korean Perl Workshop 2012 9

* 코드 출처: perlretut

• 간단한 예 "cats and dogs" =~ / dog | cat | bird /x;

• 후보들의 순서에 무관하게, 앞에서부터 일치

Korean Perl Workshop 2012 10

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs'

Korean Perl Workshop 2012 11

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+"/;

Greedy quantifier

Korean Perl Workshop 2012 12

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+?"/; Non-greedy quantifier로 교체

Korean Perl Workshop 2012 13

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+?"/; 성공!

Korean Perl Workshop 2012 14

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+?" dogs/; 뒤에 조건이 추가

Korean Perl Workshop 2012 15

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+?" dogs/;

이것을 기대하지만…

Korean Perl Workshop 2012 16

우리가 원한 것

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+?" dogs/;

???

Korean Perl Workshop 2012 17

우리가 원한 것 실제로 일치하는 부분

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/".+?" dogs/;

Non-greedy 수량자는 정규식이 일치할 때까지

문자열을 소모하며 일치부를 확장지킨다.

Korean Perl Workshop 2012 18

실제로 일치하는 부분

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/"[^"]+" dogs/; /./ 대신에 따옴표를 제외한 문자들만 일치하도록 수정

Korean Perl Workshop 2012 19

• 수량자와 같이 사용할 때 '"10" cats and "20" dogs' =~ m/"[^"]+" dogs/; 성공

Korean Perl Workshop 2012 20

• 경계가 한 글자가 아니면…… "<b>10</b> cats and <b>20</b> dogs"

Korean Perl Workshop 2012 21

• 경계가 한 글자가 아니면…… "<b>10</b> cats and <b>20</b> dogs" =~ m'<b>((?!</b>).)+</b> dogs'; 부정 전방탐색

Negative Lookahead

Korean Perl Workshop 2012 22

같은 위치에서는 왼쪽 후보부터

"Her name is Janet." =~ / Jane | Janet /x; 이 문자열은…

Korean Perl Workshop 2012 23

* 코드 출처: perlretut

"Her name is Janet." =~ / Jane | Janet /x; 이 문자열은…

절대로 'Janet'에 일치하지 않을 것임

Korean Perl Workshop 2012 24

"Her name is Janet." =~ / Janet | Jane /x / \bJane\b | \bJanet\b /x / \bJanet?\b /x 정규식 리터럴에서는 이런 실수가 적지만, 패턴이 변수에 들어가 있으면 눈에 띄지 않음

Korean Perl Workshop 2012 25

실패하면 거기서 끝나지 않는다

• 일치에 실패하면, 문자열의 다음 글자부터 다시 일치를 시도함

Korean Perl Workshop 2012 26

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; "TGA" codon의 위치를 검색

Korean Perl Workshop 2012 27

* 코드 출처: perlretut

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /TGA/g ) { print "TGA at ", pos $dna, "\n"; } 1차 시도

Korean Perl Workshop 2012 28

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 8 TGA at 18 TGA at 23

Korean Perl Workshop 2012 29

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } 2차 시도

세 글자씩 끊어가며 검색

Korean Perl Workshop 2012 30

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 18 TGA at 23 ???

… 어째서?

Korean Perl Workshop 2012 31

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 18 마지막으로 성공한 후

Korean Perl Workshop 2012 32

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 18 마지막으로 성공한 후 그 직후부터 일치를 시도하여 실패하고

Korean Perl Workshop 2012 33

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 18 마지막으로 성공한 후 그 직후부터 일치를 시도하여 실패하고 그 다음 글자부터 재시도하여 실패하고

Korean Perl Workshop 2012 34

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 18 마지막으로 성공한 후 그 직후부터 일치를 시도하여 실패하고 그 다음 글자부터 재시도하여 실패하고 TGA at 23 그 다음 글자부터 재시도하여 성공

Korean Perl Workshop 2012 35

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /\G(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; }

3차 시도

/\G/ - /g flag를 사용하여 일치된 마지막 지점

Korean Perl Workshop 2012 36

# "ATC GTT GAA TGC AAA TGA CAT GAC" $dna = "ATCGTTGAATGCAAATGACATGAC"; while ( $dna =~ /\G(\w\w\w)*?TGA/g ) { print "TGA at ", pos $dna, "\n"; } TGA at 18 성공 앵커에 일치해야 하기 때문에, 그 다음 글자부터 진행할 수 없다

Korean Perl Workshop 2012 37

Korean Perl Workshop 2012 38

“…하지 않은 것”을 찾기

• 완전한 단어 “cat”에 일치 /\bcat\b/

Korean Perl Workshop 2012 39

• 완전한 단어 “cat”에 일치 /\bcat\b/ • 어딘가에 포함되어 있는 “cat”?

Korean Perl Workshop 2012 40

• 완전한 단어 “cat”에 일치 /\bcat\b/ • 어딘가에 포함되어 있는 “cat”?

• “cat”을 제외한 모든 단어?

Korean Perl Workshop 2012 41

• 완전한 단어 “cat”에 일치 /\bcat\b/ • 어딘가에 포함되어 있는 “cat”?

• “cat”을 제외한 모든 단어?

• “cat”이 포함되지 않은 단어?

Korean Perl Workshop 2012 42

• 어딘가에 포함되어 있는 “cat”

bobcat, category, staccato, 123cat456 …

Korean Perl Workshop 2012 43

* 코드 출처: 한 권으로 끝내는 정규표현식, 67

• 어딘가에 포함되어 있는 “cat”

bobcat, category, staccato, 123cat456 …

• 오답 /\Bcat\B/

Korean Perl Workshop 2012 44

• 어딘가에 포함되어 있는 “cat”

bobcat, category, staccato, 123cat456 …

• 오답 /\Bcat\B/

• 정답 /\Bcat|cat\B/

Korean Perl Workshop 2012 45

• “cat”을 제외한 모든 단어 snake, bat, dog, bobcat, …

Korean Perl Workshop 2012 46

* 코드 출처: 한 권으로 끝내는 정규표현식, 372

• “cat”을 제외한 모든 단어 snake, bat, dog, bobcat, …

• 흔히 보이는 오답

/\b[^cat]+\b/ – [^…]를 단어를 배제하는 용도로 쓰면 안 됨

Korean Perl Workshop 2012 47

• “cat”을 제외한 모든 단어 snake, bat, dog, bobcat, …

• 흔히 보이는 오답

/\b[^cat]+\b/ – [^…]를 단어를 배제하는 용도로 쓰면 안 됨

• 마찬가지

/\b[^c][^a][^t]\b/

Korean Perl Workshop 2012 48

• “cat”을 제외한 모든 단어 snake, bat, dog, bobcat, …

• 정답

/\b(?!cat\b)\w+/

Korean Perl Workshop 2012 49

• “cat”이 포함되어 있지 않은 모든 단어 snake, bat, dog, bobcat, …

/\b(?:(?!cat)\w)+\b/

Korean Perl Workshop 2012 50

* 코드 출처: 한 권으로 끝내는 정규표현식

“일치하지 않음” vs “아닌 것에 일치함”

$str = 'I paid $30 for 100 apples';

Korean Perl Workshop 2012 51

* 코드 출처: 손에 잡히는 정규표현식, 93

$str = 'I paid $30 for 100 apples'; # 가격에만 일치 $str =~ /\$\d+/;

Korean Perl Workshop 2012 52

$str = 'I paid $30 for 100 apples'; # '$'는 제외하고 숫자에만 일치 $str =~ /(?<=\$)\d+/; # 후방탐색

Korean Perl Workshop 2012 53

my $str = 'I paid $30 for 100 apples'; # 가격이 아닌 수량에만 일치?? $str =~ /(?<!\$)\d+/; # 부정형 후방탐색

Korean Perl Workshop 2012 54

my $str = 'I paid $30 for 100 apples'; # 가격이 아닌 수량에만 일치?? $str =~ /(?<!\$)\d+/; # 부정형 후방탐색 # 실패

Korean Perl Workshop 2012 55

my $str = 'I paid $30 for 100 apples'; # 가격이 아닌 수량에만 일치?? $str =~ /(?<!\$)\d+/; # 부정형 후방탐색 # 실패 $str =~ /\b(?<!\$)\d+/; # 앵커가 필요함

Korean Perl Workshop 2012 56

전후방탐색의 활용

(?<=before)match(?=after)

이 형태만 생각하기 쉬움

Korean Perl Workshop 2012 57

일련의 숫자, 그 뒤에 일련의 문자 형태

# 1a, 1ab, 123abcd, .... /^\d+[a-z]+$/

Korean Perl Workshop 2012 58

• 전체 문자열이 4~6 글자인 것만 /^\d{1}(?:[a-z]){3,5}$/ | /^\d{2}(?:[a-z]){2,4}$/ | /^\d{3}(?:[a-z]){1,3}$/ | /^\d{4}(?:[a-z]){1,2}$/ | /^\d{5}(?:[a-z]){1}$/ … 무리입니다

Korean Perl Workshop 2012 59

• 정규식 안의 Perl 코드 /^(\d++) (??{ my $d = length($1); # 숫자열의 길이에 따라 my $min = 4-$d; # 문자열의 최소 최대 길이를 $min = 1 if $min < 1;# 결정하고 my $max = 6-$d; "[a-z]{$min,$max}"; # 정규식을 구성 }) $/x; … 무리입니다

Korean Perl Workshop 2012 60

• 정규식과 코드의 협동

/^\d+[a-z]+$/ and length($_) >= 4 and length($_) <= 6

Korean Perl Workshop 2012 61

• 전방탐색

/^(?=.{4,6}$)\d+[a-z]+$/ 둘 이상의 조건을 동시에 검사

Korean Perl Workshop 2012 62

전방탐색과 조건식 결합

올바른 우편번호 찾기 11111 (o) 22222 (o) 33333- (x) 44444-4444 (o)

Korean Perl Workshop 2012 63

* 코드 출처: 손에 잡히는 정규표현식, 102

올바른 우편번호 찾기 11111 (o) 22222 (o) 33333- (x) 44444-4444 (o) /\d{5}(-\d{4})?/ 세번째 문자열을 걸러내지 못함

Korean Perl Workshop 2012 64

올바른 우편번호 찾기 11111 (o) 22222 (o) 33333- (x) 44444-4444 (o) /\d{5}(?(?=-)-\d{4})/ 전방탐색이 성공하면 그 뒤의 패턴도 검사

Korean Perl Workshop 2012 65

Case shifting

\Q \L \l \U \u \E

– Perl에서는 큰따옴표 문자열 문법의 일부

– 정규표현식 문법이 아님

Korean Perl Workshop 2012 66

$str1 = "\uhello"; # $str1 = 'Hello' 'Hello' =~ /$str1/; # 일치됨

Korean Perl Workshop 2012 67

$str1 = "\uhello"; # $str1 = 'Hello' 'Hello' =~ /$str1/; # 일치됨 $str2 = '\uhello'; # $str2 = '\uhello' 'Hello' =~ /$str2/; # 런타임 에러

“Unrecognized escape \u …”

• 사용자 입력을 받은 경우도 마찬가지

Korean Perl Workshop 2012 68

• 쌍따옴표 문자열 내에 적용되는 순서 – 변수 치환 – 이스케이프, 논리 캐릭터 – Case shift

$ perl -e 'print "\QP*rl\n"' P\*rl\ <- (\n 있음)

Korean Perl Workshop 2012 69

• 정규표현식에 적용되는 순서 – 변수 치환 – Case shift – 이스케이프, 논리 캐릭터

Korean Perl Workshop 2012 70

• 묘하다 "\n" =~ qr/\n/ # 일치 "\n" =~ qr/\Q\n/ # 불일치 (qr/\\n/, '\n'에 일치) "\n" =~ qr/\U\n/ # 불일치! (qr/\N/, Perl5.8 이하 에러) "\n" =~ qr/\l\n/ # 일치! "\n" =~ qr/\L\n/ # 일치!

Korean Perl Workshop 2012 71

• 심지어 "\Q\n" =~ qr/\Q\n/ # 불일치 "\U\n" =~ qr/\U\n/ # 불일치 "\L\n" =~ qr/\L\n/ # 일치

Korean Perl Workshop 2012 72

Korean Perl Workshop 2012 73

/x flag

$str = "abc - 123"; $str =~ /\S+ - \d+/; 아주 잘 일치함

Korean Perl Workshop 2012 74

$str = "abc - 123"; $str =~ / \S+ # 단어 - # 대시 \d+ # 숫자 /x;

이것은 일치하지 않는다!

Korean Perl Workshop 2012 75

$str = "abc - 123"; $str =~ / \S+\ # 단어,공백 -\ # 대시,공백 \d+ # 숫자 /x;

스페이스는 /[ ]/ 또는 /\ /로 바꿔야 되는 걸 잊지 말자

Korean Perl Workshop 2012 76

Perl 5.10 ~ Perl 5.14 에서 도입된 문법들 \N 메타캐릭터

Relative Backreferences \g{3} \g{-2}

Named Backreferences (?<year>) \g<year>

Branch Reset

PREMATCH, MATCH, POSTMATCH

Possessive Quantifier <[^>]++>, 백트래킹하지 않는 부분식

/r flag

Named Subpattern

Recursive Pattern

Korean Perl Workshop 2012 77

\N metacharacter

/./ 임의의 캐릭터 하나

– /s 옵션이 있을 때는 뉴라인"\n"에 일치

– 없을 때는 뉴라인에 일치하지 않음

/\N/ /s 옵션에 무관하게 항상 뉴라인을 제외한

임의의 캐릭터 하나

78 Korean Perl Workshop 2012

Relative backreferences

# 오동작 my $a99a = '([a-z])(\d)\g2\g1'; # a11a, g22g, ... my $line = 'code=e99e'; if ( $line =~ /^(\w+)=$a99a$/ ) { print "$1 is valid\n"; }

앞에 괄호가 추가되면서 번호가 안 맞는다

Korean Perl Workshop 2012 79

* 코드 출처: perlretut

# 오동작 my $a99a = '([a-z])(\d)\g2\g1'; # a11a, g22g, ... my $line = 'code=e99e'; if ( $line =~ /^(\w+)=$a99a$/ ) { print "$1 is valid\n"; } my $a99a = '([a-z])(\d)\g{-1}\g{-2}' 현재 위치 기준.

Korean Perl Workshop 2012 80

Named backreferences

• 매치되는 그룹에 이름을 붙임

• 앞의 예 다시 my $a99a = '(?<char>[a-z])(?<digit>\d)\g{digit}\g{char}';

Korean Perl Workshop 2012 81

• 그룹의 순서가 서로 다른 패턴을 일괄처리 $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"; } } 정규식 외부에서는 %+ 해시를 써서 접근

Korean Perl Workshop 2012 82

* 코드 출처: perlretut

Branch Reset

$time = '2305'; if ( $time =~ /(\d\d|\d):(\d\d)|(\d\d)(\d\d)/ ) { print "hour = $1 minute = $2\n"; # ?? print "hour = $3 minute = $4\n"; # ?? }

몇 번째 그룹에 캡처가 될 지 모름

defined 검사 필요

Korean Perl Workshop 2012 83

* 코드 출처: perlretut

$time = '2305 GMT'; if ( $time =~ /(?|(\d\d|\d):(\d\d)|(\d\d)(\d\d))\s+([A-Z]{3})/ ) { print "hour = $1 minute = $2 zone = $3\n"; } (?| 후보1 | 후보2 | 후보3 | … )

Korean Perl Workshop 2012 84

$time = '2305 GMT'; if ( $time =~ /(?|(\d\d|\d):(\d\d)|(\d\d)(\d\d))\s+([A-Z]{3})/ ) { print "hour = $1 minute = $2 zone = $3\n"; } 각 후보들마다 그룹 번호가 동일하게 시작

Korean Perl Workshop 2012 85

1 1 2 2 3

• 각 후보 패턴마다 그룹의 개수가 다를 경우, 리셋 그룹 이후 나타나는 그룹은 가장 높은 번호의 다음 번호부터 할당

• 주의: Perl 5.14 전 버전에는 버그 • 의도한 대로 캡처되지 않음

• 캡처 그룹이 가장 많은 후보 패턴을 제일 먼저 적어주거나

• 빈 그룹 ()을 넣어 모든 후보의 그룹 개수를 동일하게 만들 것

Korean Perl Workshop 2012 86

PREMATCH, MATCH, POSTMATCH

$` $& $'

• 정규식 연산에 성능 저하를 가져옴

• 코드 내에 한 번이라도 사용되면, 모든 정규식 연산마다 저 변수들을 세팅하는 과정을 거침

Korean Perl Workshop 2012 87

* 코드 출처: www.effectiveperlprogramming.com

'My cat is Buster Bean' =~ m/Buster/; print "I matched $&\n"; # 여기서 매치 변수를 사용해버렸기 때문에 while (<>) { next unless /Bean/; # 매치할 때마다 매번 오버헤드가 발생 }

Korean Perl Workshop 2012 88

따라서, 저 세 가지 변수는

• 전혀 사용하지 않거나

• 한 번이라도 사용했다면, 그 다음은 마음대로 사용해도 됨

Korean Perl Workshop 2012 89

대신 다음 변수들을 사용

• ${^PREMATCH} $` 역할 • ${^MATCH} $& • ${^POSTMATCH} $' • /p flag 명시

• /p flag가 있는 연산에서만 오버헤드 발생

Korean Perl Workshop 2012 90

'My cat is Buster Bean' =~ m/\s\w+\sBean/p; # /p 옵션 사용 say "I matched ${^MATCH}"; while (<>) { next unless /Bean/; # 오버헤드 없음 }

Korean Perl Workshop 2012 91

5.10 전 버전 - 캡처 그룹과 매칭 변수로 대체

• /pattern/ + $` 대신 /(.*?)pattern/ + $1 • /pattern/ + $& 대신 /(pattern)/ + $1 • /pattern/ + $' 대신 /pattern(.*)/ + $+

• use English qw(-no_match_vars)

• 로드한 외부 모듈에서 사용해 버리면 역시 소용 없음

Korean Perl Workshop 2012 92

Possessive quantifier

'abcdZ' =~ /[a-d]+Z/;

93 Korean Perl Workshop 2012

'abcdZ' =~ /[a-d]+Z/; • [a-d]+는 'abcd'까지 일치

94 Korean Perl Workshop 2012

'abcdZ' =~ /[a-d]+Z/; • [a-d]+는 'abcd'까지 일치

• Z는 'Z'에 일치

95 Korean Perl Workshop 2012

'abcdZ' =~ /[a-d]+Z/; • [a-d]+는 'abcd'까지 일치

• Z는 'Z'에 일치

• 끝~

96 Korean Perl Workshop 2012

'abcda' =~ /[a-d]+Z/; # 일치하지 않는 문자열

Korean Perl Workshop 2012 97

'abcda' =~ /[a-d]+Z/; # 일치하지 않는 문자열 • [a-d]+ 는 일단 'abcda' 에 일치

Korean Perl Workshop 2012 98

'abcda' =~ /[a-d]+Z/; # 일치하지 않는 문자열 • [a-d]+ 는 일단 'abcda' 에 일치 • Z가 일치될 문자열이 남아 있지 않으므로

Korean Perl Workshop 2012 99

'abcda' =~ /[a-d]+Z/; # 일치하지 않는 문자열 • [a-d]+ 는 일단 'abcda' 에 일치 • Z가 일치될 문자열이 남아 있지 않으므로

– 'a'를 내어놓고 재시도

Korean Perl Workshop 2012 100

'abcda' =~ /[a-d]+Z/; # 일치하지 않는 문자열 • [a-d]+ 는 일단 'abcda' 에 일치 • Z가 일치될 문자열이 남아 있지 않으므로

– 'a'를 내어놓고 재시도 – 'd'를 내어놓고 재시도 – …

Korean Perl Workshop 2012 101

'abcda' =~ /[a-d]+Z/; # 일치하지 않는 문자열 • [a-d]+ 는 일단 'abcda' 에 일치 • Z가 일치될 문자열이 남아 있지 않으므로

– 'a'를 내어놓고 재시도 – 'd'를 내어놓고 재시도 – …

• 'bcda'를 대상으로 처음부터 다시 – …

Korean Perl Workshop 2012 102

'abcda' =~ /[a-d]+Z/;

Korean Perl Workshop 2012 103

;;;;;;;

그, 그만…

Korean Perl Workshop 2012 104

• 독점적인 수량자

?+ *+ ++ {2,5}+

• 일치에 성공한 부분은 백트래킹하지 않음

Korean Perl Workshop 2012 105

'abcda' =~ /[a-d]++Z/;

Korean Perl Workshop 2012 106

'abcda' =~ /[a-d]++Z/; • [a-d]++ 는 'abcda'에 일치

Korean Perl Workshop 2012 107

'abcda' =~ /[a-d]++Z/; • [a-d]++ 는 'abcda'에 일치

• Z는 일치에 실패

Korean Perl Workshop 2012 108

'abcda' =~ /[a-d]++Z/; • [a-d]++ 는 'abcda'에 일치

• Z는 일치에 실패

• 백트래킹하지 않고 곧바로 실패 판정

Korean Perl Workshop 2012 109

'abcda' =~ /[a-d]++Z/; • [a-d]++ 는 'abcda'에 일치

• Z는 일치에 실패

• 백트래킹하지 않고 곧바로 실패 판정

• 단, 여기서 끝은 아님 – 문자열의 다음 위치에서 재시도

Korean Perl Workshop 2012 110

Korean Perl Workshop 2012 111

• 주의 'aaaaa' =~ /a++a/; 이것은 일치하지 않는다

• a++가 'aaaaa'에 일치해버리기 때문에 뒤에 a가 일치할 문자열이 남지 않음

• 아무 때나 Greedy 수량자 대신 사용할 수는 없음

Korean Perl Workshop 2012 112

• 독점적 수량자를 써도 괜찮은지 판단 'aaaaa' =~ / a++ a /x; # No 'aaaaa' =~ / a++ b /x; # Yes

Korean Perl Workshop 2012 113

• 독점적 수량자를 써도 괜찮은지 판단 'aaaaa' =~ / a++ a /x; # No 'aaaaa' =~ / a++ b /x; # Yes

• 수량자가 적용되는 부분의 패턴이, 뒤에 오는 패턴과

일치하지 않으면 괜찮음

Korean Perl Workshop 2012 114

백트래킹을 하지 않는 부분식

• 독점적 수량자의 일반형

/[a-d]++Z/ /(?>[a-d]+)Z/; • 주의 /(?>[a-d])+Z/; # 다르다

Korean Perl Workshop 2012 115

/r flag in substitution

$str =~ s/pattern/replacement/ • $str 의 내용을 변경

• 치환 횟수를 반환

$str =~ s/pattern/replacement/r • $str 을 변경하지 않음

• 복제본을 만들어서 복제본을 변경

• 변경된 복제본 문자열을 반환

Korean Perl Workshop 2012 116

• 기존 코드 my $old = 'hello'; (my $new = $old) =~ s/h/H/; # 괄호 필수!

• 새 코드 my $old = 'hello'; my $new = $old =~ s/h/H/r;

Korean Perl Workshop 2012 117

그게 뭐야

Korean Perl Workshop 2012 118

• 좀 더 유용한 예 my @in = qw( Bu1s5ter Mi6mi Roscoe Gin98ger El123la ); # @in의 각 원소에서 숫자를 제거하여 # @out 배열에 저장하고 싶다 my @out = map { my $s = $_; $s =~ s/\d+//g; $s } @in; # 원소를 일일이 복사해야 함

Korean Perl Workshop 2012 119

* 코드 출처: www.effectiveperlprogramming.com

• 좀 더 유용한 예 my @in = qw( Bu1s5ter Mi6mi Roscoe Gin98ger El123la ); # @in의 각 원소에서 숫자를 제거하여 # @out 배열에 저장하고 싶다 my @out = map { my $s = $_; $s =~ s/\d+//g; $s } @in; # 원소를 일일이 복사해야 함 my @out = map { s/\d+//gr } @in;

Korean Perl Workshop 2012 120

Named Subpattern

"수"에 일치되는 정규식의 예 (3, -7, .25, 12.34, -5.67e10 등)

/^ [+-]?\ * # 먼저, 부호와 공백에 매치 ( # 그 다음 정수 또는 소수의 유효숫자부에 매치 \d+ # a로 시작하면서... ( \.\d* # a.b 또는 a. 형태의 유효숫자 )? # ?는 a 형태의 정수가 오는 경우를 고려한 것 |\.\d+ # .b 형태의 유효숫자 ) ([eE][+-]?\d+)? # 추가적으로 올 수 있는 지수부에 매치 $/x;

Korean Perl Workshop 2012 121

* 코드 출처: perlretut

패턴을 정의하고 이름을 붙인 후 재사용 /^ (?&osg)\ * ( (?&int)(?&dec)? | (?&dec) ) (?: [eE](?&osg)(?&int) )? $ (?(DEFINE) (?<osg>[-+]?) # 생략 가능한 부호 (?<int>\d++) # 정수 (?<dec>\.(?&int)) # 소수부 )/x;

Korean Perl Workshop 2012 122

Recursive Pattern

• 부등호로 둘러싸인 문자열에 일치 /<.*?>/ 또는 /<[^<>]>/

Korean Perl Workshop 2012 123

• 부등호로 둘러싸인 문자열에 일치 /<.*?>/ 또는 /<[^<>]>/

• 중첩된 형태에도 일치 "< … < … > … < … < … > > … >"

/????/

Korean Perl Workshop 2012 124

• 정규식은 정규문법으로 생성되는 문자열을 표현

• 문맥 무관 문법으로 생성되는 문자열을 표현하는 것에는 한계가 있음 – Balanced text

– Program code

• Text::Balanced

• Regexp::Common

• Parser용 모듈들

Korean Perl Workshop 2012 125

• 재귀 패턴을 사용한 정규식

중첩되지 않는 패턴 <[^<>]++>

Korean Perl Workshop 2012 126

• 재귀 패턴을 사용한 정규식

중첩되지 않는 패턴 <[^<>]++> 중첩된 패턴 = < > 안에 부등호를 제외한 것들 또는 패턴 이 반복 Korean Perl Workshop 2012 127

/ < > /x; # 부등호 안에

Korean Perl Workshop 2012 128

/ < > /x; # 부등호 안에 / < [^<>]++ > /x; # 부등호 외의 것들

Korean Perl Workshop 2012 129

/ < > /x; # 부등호 안에 / < [^<>]++ > /x; # 부등호 외의 것들 / (< [^<>]++ | (?1) >) /x; # 또는 패턴이

Korean Perl Workshop 2012 130

/ < > /x; # 부등호 안에 / < [^<>]++ > /x; # 부등호 외의 것들 / (< [^<>]++ | (?1) >) /x; # 또는 패턴이 / (< (?: [^<>]++ | (?1) )* >) /x; # 반복

Korean Perl Workshop 2012 131

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) )* > )/xg;

Korean Perl Workshop 2012 132

* 코드 출처: perlfaq6

좋죠?

Korean Perl Workshop 2012 133

그러니

Korean Perl Workshop 2012 134

호스팅 업체 분들,

Perl 5.14 이상으로 설치 좀 굽신굽신

Korean Perl Workshop 2012 135

자잘한 팁들

Korean Perl Workshop 2012 136

빈 패턴은 항상 일치

/()/

언제나 일치하며, 캡처됨

/(?!)/

언제나 실패하는 패턴

Korean Perl Workshop 2012 137

• 세 단어가 순서 무관하게 가까이 붙어 있는 경우를 검색

… word1 … word3 … … … word2 …

(8단어 이내에 세 단어 존재)

Korean Perl Workshop 2012 138

* 코드 출처: 한 권으로 끝내는 정규표현식

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x

Korean Perl Workshop 2012 139

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x 일단 word1 이 일치하면 ()가 같이 일치하고

\1은 그때부터 일치

Korean Perl Workshop 2012 140

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x 일단 word1 이 일치하면 ()가 같이 일치하고

\1은 그때부터 일치

Korean Perl Workshop 2012 141

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x 일단 word1 이 일치하면 ()가 같이 일치하고

\1은 그때부터 일치

Korean Perl Workshop 2012 142

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x 일단 word1 이 일치하면 ()가 같이 일치하고

\1은 그때부터 일치

Korean Perl Workshop 2012 143

이제부터는 아무 단어나 일치 가능

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x 일단 word1 이 일치하면 ()가 같이 일치하고

\1은 그때부터 일치

Korean Perl Workshop 2012 144

최대 8번까지 단어들을 일치시킨 후

… word1 … word3 … … … word2 …

/ \b (?: (?>word1()|word2()|word3()|(?>\1|\2|\3)\w+)\b\W*? ){3,8} \1\2\3 /x 일단 word1 이 일치하면 ()가 같이 일치하고

\1은 그때부터 일치

Korean Perl Workshop 2012 145

전체 패턴이 일치하기 위해서는 여기를 통과해야 함 즉 word1, word2, word3 이 한번씩 일치되었어야 함

Korean Perl Workshop 2012 146

정규식으로만 해결하려 하지 말자

my $str = '1 <b>2</b> 3 4 <b>5 6 7</b> 8'; # 볼드체로 표시되는 숫자들만 추출하고 싶다 # 2, 5, 6, 7 # "5 6 7"을 추출하는 게 아니라서 까다롭다

Korean Perl Workshop 2012 147

my $str = '1 <b>2</b> 3 4 <b>5 6 7</b> 8'; # 볼드체로 표시되는 숫자들만 추출하고 싶다 # 2, 5, 6, 7 my @numbers = ( $str =~ m|\d+(?=(?:(?!<b>).)*</b>)|g );

Korean Perl Workshop 2012 148

my $str = '1 <b>2</b> 3 4 <b>5 6 7</b> 8'; # 볼드체로 표시되는 숫자들만 추출하고 싶다 # 2, 5, 6, 7 while ( $str =~ m|<b>(.*?)</b>|gs ) { push @numbers, ($& =~ /\d+/g); } 쉽고, 백트래킹 등을 생각하면 효율도 이게 낫다

Korean Perl Workshop 2012 149

grep

grep '\d\{4\}\s\+' file1 file2 백슬래시 쓰느라 지겨우시죠?

Korean Perl Workshop 2012 150

grep '\d\{4\}\s\+' file1 file2 grep -P '\d{4}\s+' file1 file2 Perl 정규식을 사용 가능

Korean Perl Workshop 2012 151

vim

/\(a\|b\)\+

• vim의 패턴 해석 방식 4가지 – \V : 백슬래시만 특수하게 해석 – \M : set nomagic – \m : set magic – \v : "very magic"

• Perl 정규식과 비슷해짐 /\v(a|b)+

Korean Perl Workshop 2012 152

• vim의 Lookaround – \@= \@! Lookahead – \@<= \@<! Lookbehind

• 예 /foo\(bar\)\@! "bar"가 뒤에 오지 않는 "foo"

:help pattern :help perl-patterns

Korean Perl Workshop 2012 153

Regexp::Debugger

• Damian Conway

• CPAN

use Regexp::Debugger; 또는

$ rxrx

Korean Perl Workshop 2012 154

"감사합니다" =~

/(Q(&A)?)*/

Korean Perl Workshop 2012 155