Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<h1>캡쳐 그룹</h1> <p>Groovy의 매우 유용한 기능 중 하나는 정규식을 이용하여 데이터에서 특정 부분을 잡아내는 것입니다. 아래 데이터에서 각 요소를 뽑아내고 싶다고 가정해봅시다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> locationData = "Liverpool, England: 53° 25? 0? N 3° 0? 0?" </pre></td></tr></table> <p>물론 String의 split() 메서드를 이용하여 잘라낸 후 Livepool과 England 사이의 ","를 제거하고, 나머지 조각들에 대해서도 비슷한 작업을 반복해주면 되긴 합니다. 하지만 정규식을 이용하면 이 작업을 한번에 끝낼 수 있습니다. 이 작업을 위한 문법은 약간 특이합니다. 우선 정규식을 작성하고 뽑아내고자 하는 부분을 괄호 안에 넣으세요:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> myRegularExpression = /([a-zA-Z]+), ([a-zA-Z]+): ([0-9]+). ([0-9]+). ([0-9]+). ([A-Z]) ([0-9]+). ([0-9]+). ([0-9]+)./ </pre></td></tr></table> <p>다음으로는 <strong>=~</strong> 연산자로 "matcher"를 정의해야 합니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> matcher = ( locationData =~ myRegularExpression ) </pre></td></tr></table> <p>이제 matcher 변수는 java.util.regex.Matcher 클래스의 인스턴스를 갖게 됩니다. 물론 Groovy에 의해 확장된 추가 기능도 함께 들어 있습니다. 자바 방식으로 Matcher 객체를 사용할 수도 있지만, 더 Groovy 적인 방법은 Matcher 객체를 마치 2차원 배열인 것 처럼 취급하는 것입니다. 2차원 배열이란 단순히 배열의 배열을 말합니다. 배열의 첫번째 차원에는 이 정규직에 의해 일치된 문자열들이 담깁니다. 이 예제에서는 정규식에 대해 전체 문자열이 단 한번 일치되었기 때문에 첫번째 차원의 길이는 1 입니다. 따라서 다음과 같이 쓰면:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> matcher[0] </pre></td></tr></table> <p>다음과 같이 평가됩니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> ["Liverpool, England: 53° 25? 0? N 3° 0? 0?", "Liverpool", "England", "53", "25", "0", "N", "3", "0", "0"] </pre></td></tr></table> <p>이제 두번째 차원을 이용하여 각 캡쳐 그룹에 접근할 수 있습니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> if (matcher.matches()) { println(matcher.getCount()+ " occurrence of the regular expression was found in the string."); println(matcher[0][1] + " is in the " + matcher[0][6] + " hemisphere. (According to: " + matcher[0][0] + ")") } </pre></td></tr></table> <p>정규식을 이용해서 얻을 수 있는 추가적인 장점은 주어진 데이터의 형식이 적합한지를 검사할 수 있다는 사실입니다. 즉, *locationData*의 내용이 "Could not find location data for Lima, Peru" 였다면 위 if 문 안의 블록은 실행되지 않을 것입니다.</p> <h1>비 캡쳐 그룹(Non-matching groups)</h1> <p>가끔, 괄호로 표현을 묶고 싶기는 한데 그 괄호가 캡쳐 그룹으로 사용되는 것은 원하지 않을 때가 있습니다. 이럴때는 괄호 바로 다음에 ?: 를 붙여주면 됩니다. 예를 들어 사람들의 이름 표기를 바꾸고 싶은데 중간 이름(middle name)은 무시하고자 한다면 아래와 같이 쓸 수 있습니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> names = [ "Graham James Edward Miller", "Andrew Gregory Macintyre" ] printClosure = { matcher = (it =~ /(.*?)(?: .+)+ (.*)/); // notice the non-matching group in the middle if (matcher.matches()) println(matcher[0][2]+", "+matcher[0][1]); } names.each(printClosure); </pre></td></tr></table> <p>결과는 아래와 같습니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> Miller, Graham Macintyre, Andrew </pre></td></tr></table> <p>이렇게 하면 성(last name)이 항상 두번째 캡쳐 그룹에 잡히게 됩니다.</p> <h2>바꾸기</h2> <p>정규식의 단순하지만 정말 강력한 기능 중 하나는 문자열에서 특정 패턴을 찾아서 다른 문자열로 바꿔주는 기능입니다. java.util.regex.Matcher의 replaceFirst() 혹은 replaceAll() 메서드를 이용하면 됩니다.</p> <p>예를 들어, J.K. Rowlings의 책인 Harry Potter 시리즈를 다른 이름으로 팔아먹기 위해 문자열 중에 나오는 모든 "Harry Potter"를 "Tanya Grotter"로 치환해봅시다. (정말 이짓을 한 사람이 있습니다. 못 믿겠으면 구글에서 찾아보세요):</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> excerpt = "At school, Harry had no one. Everybody knew that Dudley's gang hated that odd Harry Potter "+ "in his baggy old clothes and broken glasses, and nobody liked to disagree with Dudley's gang."; matcher = (excerpt =~ /Harry Potter/); excerpt = matcher.replaceAll("Tanya Grotter"); matcher = (excerpt =~ /Harry/); excerpt = matcher.replaceAll("Tanya"); println("Publish it! "+excerpt); </pre></td></tr></table> <p>위 예제에서는 두 번의 치환 작업을 수행했습니다. 한번은 전체 이름인 "Harry Potter"에 대해, 또 한번은 이름인 "Harry"에 대해서만.</p> <h2>릴럭턴트(reluctant) 연산자</h2> <p>?, + 그리고 * 연산자는 모두 기본적으로 그리디(greedy - 욕심많은) 입니다. 즉, 가능하면 많은 부분과 일치시키려는 특성이 있습니다. 하지만 가끔은 이런 특성을 원치 않을 때가 있습니다. 15세기 교황을 나열한 다음 예제를 살펴보겠습니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> popesArray = [ "Pope Anastasius I 399-401", "Pope Innocent I 401-417", "Pope Zosimus 417-418", "Pope Boniface I 418-422", "Pope Celestine I 422-432", "Pope Sixtus III 432-440", "Pope Leo I the Great 440-461", "Pope Hilarius 461-468", "Pope Simplicius 468-483", "Pope Felix III 483-492", "Pope Gelasius I 492-496", "Pope Anastasius II 496-498", "Pope Symmachus 498-514" ] </pre></td></tr></table> <p>우선 이름(예를 들어 "Pope Anastasius II" 에서 "Anastasius")과 연도만 정확히 추출하는 정규식을 써보겠습니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> /Pope (.*)(?: .*)? ([0-9]+)-([0-9]+)/ </pre></td></tr></table> <p>Which splits up as:</p> <table class="confluenceTable"><tbody> <tr> <td class="confluenceTd"><p> / </p></td> <td class="confluenceTd"><p> Pope </p></td> <td class="confluenceTd"><p> (.*) </p></td> <td class="confluenceTd"><p> (?: .*)? </p></td> <td class="confluenceTd"><p> ([0-9]+) </p></td> <td class="confluenceTd"><p> - </p></td> <td class="confluenceTd"><p> ([0-9]+) </p></td> <td class="confluenceTd"><p> / </p></td> </tr> <tr> <td class="confluenceTd"><p> 문장 시작 </p></td> <td class="confluenceTd"><p> Pope </p></td> <td class="confluenceTd"><p> 몇 개의 글자들을 잡아내고 </p></td> <td class="confluenceTd"><p> 비 캡쳐 그룹: 스페이스와 몇 개의 문자들 </p></td> <td class="confluenceTd"><p> 숫자를 잡아낸 후 </p></td> <td class="confluenceTd"><p> - </p></td> <td class="confluenceTd"><p> 다시 숫자 </p></td> <td class="confluenceTd"><p> 그리고 문장의 끝 </p></td> </tr> </tbody></table> <p>위 정규식에서 우리는 첫번째 캡쳐 그럼이 교황의 이름을 잡아낼 것을 기대하지만 실제로는 그렇게 되지 않습니다. 너무 많이 잡아내고 있습니다. 예를 들어 첫번째 줄은 다음과 같이 나뉩니다:</p> <table class="confluenceTable"><tbody> <tr> <td class="confluenceTd"><p> / </p></td> <td class="confluenceTd"><p> Pope </p></td> <td class="confluenceTd"><p> (.*) </p></td> <td class="confluenceTd"><p> (?: .*)? </p></td> <td class="confluenceTd"><p> ([0-9]+) </p></td> <td class="confluenceTd"><p> - </p></td> <td class="confluenceTd"><p> ([0-9]+) </p></td> <td class="confluenceTd"><p> / </p></td> </tr> <tr> <td class="confluenceTd"><p> 문장 시작 </p></td> <td class="confluenceTd"><p> Pope </p></td> <td class="confluenceTd"><p> Anastasius I </p></td> <td class="confluenceTd"><p> </p></td> <td class="confluenceTd"><p> 399 </p></td> <td class="confluenceTd"><p> - </p></td> <td class="confluenceTd"><p> 401 </p></td> <td class="confluenceTd"><p> 문장 끝 </p></td> </tr> </tbody></table> <p>첫번째 캡쳐 그룹이 너무 많은 입력을 잡아내고 있습니다. 우리가 원하는 건 "Anastasius"만 잡는 것입니다. 다시 말하면 첫번째 캡쳐 그룹은 가능한 최소한의 입력만 잡아내어야 합니다. 자바 정규식은 이런 경우에 대비하여 "reluctant" 버전의 *, +, ? 연산자를 제공합니다. 연산자 뒤에 ? 를 붙여서 *?, +?, ??와 같이 표기하면 됩니다. 다음은 이것을 적용한 새 정규식 입니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> /Pope (.*?)(?: .*)? ([0-9]+)-([0-9]+)/ </pre></td></tr></table> <p>이제 가장 복잡해보이는 입력에 대해 정규식을 적용해봅시다:</p> <table class="confluenceTable"><tbody> <tr> <td class="confluenceTd"><p> / </p></td> <td class="confluenceTd"><p> Pope </p></td> <td class="confluenceTd"><p> (.*?) </p></td> <td class="confluenceTd"><p> (?: .*)? </p></td> <td class="confluenceTd"><p> ([0-9]+) </p></td> <td class="confluenceTd"><p> - </p></td> <td class="confluenceTd"><p> ([0-9]+) </p></td> <td class="confluenceTd"><p> / </p></td> </tr> <tr> <td class="confluenceTd"><p> 문장 시작 </p></td> <td class="confluenceTd"><p> Pope </p></td> <td class="confluenceTd"><p> Leo </p></td> <td class="confluenceTd"><p> I the Great </p></td> <td class="confluenceTd"><p> 440 </p></td> <td class="confluenceTd"><p> - </p></td> <td class="confluenceTd"><p> 461 </p></td> <td class="confluenceTd"><p> 문장 끝 </p></td> </tr> </tbody></table> <p>정확히 우리가 원하는 결과입니다.</p> <p>다음 코드를 통해 위에서 설명한 내용들을 테스트할 수 있습니다:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> popesArray = [ "Pope Anastasius I 399-401", "Pope Innocent I 401-417", "Pope Zosimus 417-418", "Pope Boniface I 418-422", "Pope Celestine I 422-432", "Pope Sixtus III 432-440", "Pope Leo I the Great 440-461", "Pope Hilarius 461-468", "Pope Simplicius 468-483", "Pope Felix III 483-492", "Pope Gelasius I 492-496", "Pope Anastasius II 496-498", "Pope Symmachus 498-514" ] myClosure = { myMatcher = (it =~ /Pope (.*?)(?: .*)? ([0-9]+)-([0-9]+)/); if (myMatcher.matches()) println(myMatcher[0][1]+": "+myMatcher[0][2]+" to "+myMatcher[0][3]); } popesArray.each(myClosure); </pre></td></tr></table> <p>수정하기 전의 정규식을 사용해서 위 예제를 다시 시도해보세요. 출력이 어떻게 깨지는지 살펴볼 수 있습니다.</p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced