Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

정규식(Regular Expressions)

텍스트 처리에 있어서 정규식은 스위스 군용 칼과도 같습니다. 정규식을 이용하면 문자열에서 특정 *패턴*을 찾아내고 뽑아낼 수 있습니다. 정규식의 가장 단순한 예는 문자와 숫자로 구성된 문자열입니다. 그리고 정규식을 사용하는 가장 간단한 표현식은 *==~* 연산자를 사용하는 것입니다. So for example to match Dan Quayle's spelling of 'potato':

Code Block
"potatoe" ==~ /potatoe/

groovyConsole에 위 코드를 입력하고 실행하면 true로 평가될 것입니다. 두 가지 주목할 점이 있습니다. 첫째, ==~ 연산자는 ==와 비슷한데 정확한 문자열 일치를 검사하는 것이 아니라 정규식 패턴을 검사합니다. 둘째, 정규식이 / 로 둘러쌓여 있다는 사실입니다. 슬래시 기호는 그 안에 있는 문자열이 보통 String이 아니라 정규식이라는 사실을 알려줍니다.

올바른 철자인 "potato"와도 일치되길 원한다면 'e' 다음에 '?'를 붙여서 'e'가 생략가능하다는 점을 명시할 수 있습니다. 따라서 아래 코드는 여전히 true로 평가됩니다:

Code Block
"potatoe" ==~ /potatoe?/

그리고 올바른 철자 또한 true 입니다:

Code Block
"potato" ==~ /potatoe?/

하지만 그 외의 문자열은 false가 됩니다:

Code Block
"motato" ==~ /potatoe?/

위 예제들이 바로 정규식을 이용하여 Boolean 표현식을 정의하는 방법들입니다. 여기서 조금 더 나아가 보겠습니다. 정규식을 테스트하는 메서드를 정의하겠습니다. Pete Wisniewski의 성을 검사하는 코드입니다:

Code Block
def checkSpelling(spellingAttempt, spellingRegularExpression)
{
   if (spellingAttempt ==~ spellingRegularExpression)
   {
      println("Congratulations, you spelled it correctly.")
   } else {
      println("Sorry, try again.")
   }
}

theRegularExpression = /Wisniewski/
checkSpelling("Wisniewski", theRegularExpression)
checkSpelling("Wisnewski", theRegularExpression)

두 가지 새로운 개념이 등장했습니다. 첫째, 함수를 정의했습니다. 사실은 메서드이지만, 함수와 메서드를 같은 뜻으로 간주하고 사용하도록 하겠습니다. 함수란 코드 모음인데 클로저와 비슷합니다. 하지만 함수는 항상 이름을 갖습니다. 반면 클로저는 익명일 수도 있지요. 일단 함수를 정의했으면 나중에 언제든 불러쓸 수 있습니다.

이 함수에서는 spellingAttempt가 정규식과 일치하는지를 비교하기 위해 *==~* 연산자를 쓰고 있습니다.

여기서 더 나아가보겠습니다. 이름 중간에 'w'가 없어도 되도록 고쳐봅시다:

Code Block
theRegularExpression = /Wisniew?ski/
checkSpelling("Wisniewski", theRegularExpression)
checkSpelling("Wisnieski", theRegularExpression)
checkSpelling("Wisniewewski", theRegularExpression)

spellingRegularExpression에 추가된 *?* 문자가 의미하는 것은 그 앞에 있는 문자('w')가 생략가능하다는 것입니다. *spellingAttempt* 변수에 여러 다른 값들을 입력해서 위 코드를 실행해보면 단지 두 가지 철자("Wisniewski"와 "Wisnieski")만이 수용된다는 점을 알 수 있습니다. (checkSpelling의 정의는 고칠 필요가 없습니다)

*?* 문자는 정규식에서 특별한 의미를 가지는 문자 중 하나입니다. 모든 구두점 문자들에 특별한 의미가 있다고 보아도 됩니다.

이제 중간에 있는 'ie'가 뒤집어져도 상관없도록 만들어봅시다. 다음 코드를 보세요:

Code Block
theRegularExpression = /Wisn(ie\|ei)w?ski/
checkSpelling("Wisniewski", theRegularExpression)
checkSpelling("Wisnieski", theRegularExpression)
checkSpelling("Wisniewewski", theRegularExpression)

다시 여러 철자를 대입해보세요. 이제 네가지 철자 - "Wisniewski", "Wisneiwski", "Wisnieski", "Wisneiski" - 가 통과할 것입니다. 바(|) 문자는 그 문자 좌,우 중 한가지를 수용할 수 있음을 의미합니다. 위 경우엔 'ie' 혹은 'ei' 입니다. 괄호 표시는 바 문자가 적용되는 구간을 나타내줍니다.

다음으로 소개할 흥미로운 기능은 여러 개의 문자 중 어느 것이든 받아드려지도록 하는 것입니다. *[ ]* 기호를 사용하면 됩니다. 다음 코드를 실험해보세요:

Code Block
theRegularExpression = /Wis\[abcd\]niewski/ // 'a', 'b', 'c', 'd' 중 한가지가 나와야함
theRegularExpression = /Wis\[abcd\]?niewski/ // 'a', 'b', 'c', 'd' 중 한가지가 허용되지만 꼭 나와야 하는 것은 아님
theRegularExpression = /Wis\[a-zA-Z\]niewski/ // 영어 대문자 혹은 소문자 한 글자가 나와야 함
theRegularExpression = /Wis\[^abcd\]niewski/ // 'a', 'b', 'c', 'd'가 '''아닌''' 어떠한 한 글자가 나와야 함

위 예제에서 마지막 정규식은 설명이 필요할 것 같습니다. 꺽쇄괄호의 첫 문자가 *^* 이면 괄호 안에 있는 문자들을 제외한 어떤 문제도 허용된다는 뜻입니다.

연산자

정규식의 기본적인 작동에 대해 익혔으니 여러가지 유용한 연산자들을 살펴보겠습니다.

정규식 연자사들

a?

*a* 가 안나오거나 한번 나와야 함

'a' 혹은 빈 문자열

a*

*a* 가 안나오거나 여러번 나와야 함

빈 문자열 혹은 'a', 'aa', 'aaa' 등등

a+

*a* 가 한번 이상 나와야 함

'a', 'aa', 'aaa' 등등

a|b

*a* 혹은 *b*

'a' 혹은 'b'

.

임의의 문자 하나

'a', 'q', 'l', '_', '+' 등등

[woeirjsd]

주어진 문자 중 하나

'w', 'o', 'e', 'i', 'r', 'j', 's', 'd'

[1-9]

범위 안의 문자 중 하나

'1', '2', '3', '4', '5', '6', '7', '8', '9'

[^13579]

주어진 문자가 아닌 다른 문자 하나

열거되지 않은 숫자나 문자

(ie)

묶어주기. 다른 연산자와 함께 쓰임

'ie'

^a

문자열의 시작에 나오는 *a*

'a'

a$

문자열의 마지막에 나오는 *a*

'a'

아직 설명하지 않은 두 가지 사실이 남아 있습니다. 만약 위에 나열된 연산자 중 하나를 실제 문자로 사용하고자 한다면(예를 들면 물음표 등) 그 문자 앞에 '\'를 붙여줘야 합니다. 다음 예제를 참고하세요:

Code Block
// 물음표로 끝나는 문자열만 true로 평가됨
"How tall is Angelina Jolie?" ==~ /[^\?]+\?/

위 코드는 여러분이 보아온 정규식 중 가장 지저분할 것입니다. 이게 바로 PERL 언어가 "쓰기 전용" 언어로 불리는 이유 중 하나죠. 어쨌건, 안젤리나 졸리의 키가 얼마인지 는 구글이 알고 있습니다. 이런 종류의 표현식을 이해할 수 있는 유일한 방법은 수식을 여러 조각으로 나눠보는 것입니다:

/

[^?]

+

?

/

문장 시작

'?'가 아닌 모든 문자

가 여러개 나오고

물음표

문장 끝

? 앞에 나오는 \ 문자가 ?를 연산자가 아닌 일반 문자로 취급하도록 만든 것입니다.