regexp 패키지는 Go에서 정규 표현식을 지원해요.
Go에서 사용하는 정규 표현식의 문법은 Perl, Python을 비롯한 다른 언어에서 쓰는 일반적인 문법과 같아요.
검색 패턴과 입력 텍스트는 모두 UTF-8로 해석해요.
문자열을 만들 때 백틱(\)을 사용하면 백슬래시(\)는 특별한 의미가 없고, 탭 \t이나 줄 바꿈 \n 같은 특수 문자의 시작을 표시하지도 않아요:
"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'
그래서 정규 표현식을 만들 때는 백틱을 쓰는 게 좋아요. 백슬래시를 이스케이프할 필요가 없어지기 때문이에요:
"\\" // string with a single backslash
`\\` // string with 2 backslashes
RegExp 타입정규 표현식을 사용하려면 먼저 문자열 패턴을 컴파일해야 해요.
여기서 컴파일이란 정규 표현식의 문자열 패턴을 다루기 쉬운 내부 표현으로 변환하는 것을 말해요.
패턴은 한 번만 컴파일하면 되고, 그다음부터는 컴파일된 정규 표현식을 여러 번 사용할 수 있어요.
regexp.Regexp 타입은 컴파일된 정규 표현식을 나타내요.
regexp.Compile 함수를 사용하면 문자열 패턴을 regexp.Regexp로 컴파일할 수 있어요.
이 함수는 컴파일이 실패하면 nil과 오류를 반환해요:
re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`
MustCompile 함수는 Compile의 편리한 대안이에요:
re = regexp.MustCompile(`[a-z]+\d*`)
이 함수를 사용하면 오류를 처리할 필요가 없어요.
MustCompile은 패턴이 확실히 컴파일된다고 확신할 때만 사용해야 해요. 그렇지 않으면 프로그램이 패닉을 일으키기 때문이에요.
Regexp에는 정규 표현식과 일치하는 부분을 찾아 그 텍스트를 알려 주는 메서드가 16개 있어요.
이 메서드들의 이름은 다음 정규 표현식과 일치해요:
Find(All)?(String)?(Submatch)?(Index)?
All이 있으면 전체 표현식에서 겹치지 않는 연속된 일치를 모두 찾아요.String이 있으면 인자가 문자열이고, 없으면 바이트 슬라이스예요. 반환 값은 그에 맞게 조정돼요.Submatch가 있으면 반환 값은 표현식의 연속된 하위 일치를 나타내는 슬라이스예요.Index가 있으면 일치와 하위 일치를 입력 문자열 안의 바이트 인덱스 쌍으로 나타내요.그 밖에 다음과 같은 메서드도 있어요:
전부 합치면 regexp 패키지는 40개가 넘는 함수와 메서드를 정의해요.
아래에서 몇 가지 메서드의 사용법을 살펴볼게요.
이 메서드들과 다른 함수들의 자세한 내용은 API 문서를 참고해요.
MatchString 예제MatchString 메서드는 문자열에 정규 표현식과 일치하는 부분이 있는지 알려 줘요.
re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]") // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!") // => true
b = re.MatchString("123 456") // => false
FindString 예제FindString 메서드는 정규 표현식과 가장 왼쪽에서 일치하는 부분의 텍스트를 담은 문자열을 반환해요.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]") // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!") // => "abc"
s = re.FindString("123 456") // => ""
FindStringSubmatch 예제FindStringSubmatch 메서드는 정규 표현식과 가장 왼쪽에서 일치하는 부분과, 하위 표현식이 일치한 부분이 있다면 그 텍스트를 담은 문자열 슬라이스를 반환해요.
캡처 그룹과 일치하는 문자열을 확인할 때 사용할 수 있어요.
반환 값이 nil이면 일치하는 부분이 없다는 뜻이에요.
re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]") // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!") // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456") // => <nil>
ReplaceAllString 예제re.ReplaceAllString(src,repl) 메서드는 src의 복사본을 반환하면서, 정규 표현식 re와 일치하는 부분을 대체 문자열 repl로 바꿔요.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X") // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X") // => " X!"
s = re.ReplaceAllString("123 456", "X") // => "123 456"
Split 예제re.Split(s,n) 메서드는 텍스트 s를 표현식으로 구분되는 부분 문자열들로 나누고, 그 표현식 일치 사이에 있는 부분 문자열들의 슬라이스를 반환해요.
개수 n은 반환할 부분 문자열의 최대 개수를 정해요.
n<0이면 모든 부분 문자열을 반환해요.
re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1) // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1) // => []string{" ","!"}
sl = re.Split("123 456", -1) // => []string{"123 456"}
이 패키지가 제공하는 정규 표현식 구현은 입력 크기에 선형인 시간 안에 실행되는 것이 보장돼요.
regexp 패키지는 RE2 정규 표현식을 구현해요 (\C는 제외하고요).
이 문법은 PCRE("Perl 호환 정규 표현식")와 대체로 호환되지만 몇 가지 차이가 있어요.
자세한 내용은 이 글의 "Caveat section"을 참고해요.