ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Go] regexp 패키지와 정규표현식 알아보기
    Golang 2024. 6. 8. 13:08
    728x90
    반응형

     

    - 목차

     

    들어가며.

    Go 언어에서 regexp 패키지는 정규식(Regular Expressions) 을 통해서 문자열을 처리하고 분석하는 도구입니다.

    이번 글에서는 regexp 패키지의 기본 사용법과 실전에서 유용한 예제를 다룹니다.

     

    Golang 의 regexp 란 ?

    Goregexp 패키지는 정규식 기반으로 문자열을 매칭, 검색, 대체, 분리하는 기능을 제공합니다. 

    regexp 패키지의 대표적인 기능은 아래와 같습니다.

     

    • Compile: 정규식을 컴파일하여 Regexp 객체 생성.
    • MatchString: 문자열이 정규식에 매칭되는지 확인.
    • Find: 정규식에 매칭되는 부분 문자열 반환.
    • ReplaceAllString: 정규식에 매칭되는 부분을 다른 문자열로 대체.
    • Split: 정규식을 기준으로 문자열 분리.

     

    type Regexp struct.

    Regexp Go 의 정규식 객체를 표현하는 구조체로, 정규식 패턴을 컴파일한 결과를 담고 있습니다.

    Regexp 구조체의 구성과 설명은 아래와 같습니다.

     

    type Regexp struct {
    	expr           string       // as passed to Compile
    	prog           *syntax.Prog // compiled program
    	onepass        *onePassProg // onepass program or nil
    	numSubexp      int
    	maxBitStateLen int
    	subexpNames    []string
    	prefix         string         // required prefix in unanchored matches
    	prefixBytes    []byte         // prefix, as a []byte
    	prefixRune     rune           // first rune in prefix
    	prefixEnd      uint32         // pc for last rune in prefix
    	mpool          int            // pool for machines
    	matchcap       int            // size of recorded match lengths
    	prefixComplete bool           // prefix is the entire regexp
    	cond           syntax.EmptyOp // empty-width conditions required at start of match
    	minInputLen    int            // minimum length of the input in bytes
    
    	// This field can be modified by the Longest method,
    	// but it is otherwise read-only.
    	longest bool // whether regexp prefers leftmost-longest match
    }

     

    Complie, MustCompile, Copy 등과 같은 regexp 패키지의 함수들은 Regexp struct 를 생성합니다.

     

    Compile.

    regexp 패키지의 Compile 함수는 아래와 같은 시그니처를 가집니다.

    Compile 함수는 정규표현식 문자열을 입력값으로 받으며 Regexp 구조체의 포인터를 반환합니다.

    반환되는 Regexp 구조체는 입력값으로 주어진 정규식 패턴을 컴파일한 결과입니다.

     

    func Compile(expr string) (*Regexp, error)

     

    아래와 예시는 1개 이상의 숫자를 캡처하는 Regexp 구조체를 생성합니다.

    그리고 Regexp 의 Method 인 MatchString 을 통해서 특정 문자열이 1개 이상의 숫자를 포함하는지 여부를 판단합니다.

    ("\d+"  정규표현식은 1개 이상의 숫자를 의미합니다. )

     

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
        pattern := `\d+`
        re, _ := regexp.Compile(pattern)
        fmt.Println(re.MatchString("12345"))
        // true
    }

     

    위 예시처럼 string "12345" 은 숫자를 포함하는 문자열이기에 "\d+" 패턴을 만족합니다.

     

     

    MustCompile.

    regexp.MustCompile 는 Go 의 표준 라이브러리 regexp 패키지에서 정규식을 컴파일할 때 사용하는 함수 중 하나입니다.
    이 함수는 정규식이 유효하지 않은 경우 패닉(panic)을 발생시킨다는 점에서 일반적인 regexp.Compile 과 차이가 있습니다.

    regexp.Compile 함수는 Regex 구조체와 error 를 함께 반환하여 Caller 함수에 Error Handling 을 책임을 전가합니다.

    반면 MustCompile 은 내부적으로 에러 발생 시에 Panic 을 발생하게 되며, 이를 recover 방식으로 Error Handling 이 가능합니다.

     

    MustCompile 함수의 시그니처는 아래와 같습니다.

    func MustCompile(str string) *Regexp

     

    아래의 예시는 잘못된 Pattern 으로 MustCompile 사용 시에 발생할 수 있는 panic 과 recover 예시입니다.

    "??" 패턴은 정규표현식으로 사용될 수 없습니다.

    그 이유는 "?" 0개 이상의 반복을 의미하게 되는데요.

    그렇기 때문에 ? 앞에 반드시 특정 문자가 위치해야합니다.

     

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	pattern := `??`
    	defer func() {
    		if r := recover(); r != nil {
    			fmt.Println("Recovered from panic:", r)
    		}
    	}()
    	re := regexp.MustCompile(pattern)
    	fmt.Println(re.MatchString("12345"))
    }

     

     

    MatchString.

    regexp.MatchStringGo 의 regexp 패키지에서 제공하는 함수로, 주어진 문자열이 특정 정규식 패턴과 일치하는지 확인할 때 사용됩니다.
    이 함수는 문자열이 정규식과 매칭되면 true, 매칭되지 않으면 false를 반환합니다.

     

    MatchString 함수의 시그니처는 아래와 같습니다.

     

    func MatchString(pattern string, s string) (matched bool, err error)

     

    MatchString 함수의 사용 예시는 아래와 같습니다.

     

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	pattern := `\d{5}`
    	matched, _ := regexp.MatchString(pattern, "12345")
    	fmt.Println("matched: ", matched) //	matched:  true
    
    	matched, _ = regexp.MatchString(pattern, "123")
    	fmt.Println("matched: ", matched) //	matched:  false
    
    	matched, _ = regexp.MatchString(pattern, "abc12345qwe")
    	fmt.Println("matched: ", matched) //	matched:  true
    
    	pattern = "??"
    	_, err := regexp.MatchString(pattern, "abc12345qwe")
    	if err != nil {
    		fmt.Println("matched: ", err.Error()) //	matched:  error parsing regexp: missing argument to repetition operator: `??`
    	}
    
    }

     

    Find.

    regexp.FindGo 의 정규식 패키지 regexp 에서 특정 패턴과 매칭되는 첫 번째 문자열을 찾는 함수입니다.

    이 함수는 정규식을 사용해 주어진 입력에서 원하는 부분 문자열을 추출할 때 유용합니다.

     

    Find 의 시그니처는 아래와 같습니다.

    주목할 점은 입력과 출력값의 데이터 타입이 []byte 슬라이스 타입입니다.

     

    func (re *Regexp) Find(b []byte) []byte

     

    아래는 regexp.Find 의 활용 예시입니다.

    regexp.Find 함수는 string 과 []byte 의 변환에 유의해야합니다.

     

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	pattern := `\d{5}`
    	var re *regexp.Regexp = regexp.MustCompile(pattern)
    	var text string = "111112222233333"
    	output := re.Find(([]byte)(text))
    	fmt.Println("find: ", string(output)) // find:  11111
    }

     

     

    FindString.

    regexp.Find 함수는 []byte 타입의 입력과 출력값을 취급합니다.

    반면, string 타입의 데이터를 다루어야한다면 FindString 함수를 사용할 수 있습니다.

     

    regexp.FindString 함수의 활용 예시는 아래와 같습니다.

     

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	pattern := `\d{5}`
    	var re *regexp.Regexp = regexp.MustCompile(pattern)
    	var text string = "111112222233333"
    	output := re.FindString(text)
    	fmt.Println("find: ", output) // find:  11111
    }

     

     

    FindAll.

    Find 와 FindString 함수는 문자열에서 Pattern 과 매칭되는 첫번째 부분 문자열이 출력됩니다.

    Pattern Matching 되는 모든 부분 문자열을 추출해야한다면 FindAll 함수를 활용해야합니다.

     

    regexp.FindAll 함수의 시그니처는 아래와 같습니다.

    아래와 같이 FindAll 함수는 Regexp 구조체의 Method 로 표현됩니다.

     

    func (re *Regexp) FindAll(b []byte, n int) [][]byte

     

    regexp.FindAll 함수의 활용 예시는 아래와 같습니다.

     

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	pattern := `\d{5}`
    	var re *regexp.Regexp = regexp.MustCompile(pattern)
    	var text string = "111112222233333"
    	output := re.FindAll(([]byte)(text), 3)
    
    	for index, subStrBytes := range output {
    		fmt.Printf("find %d: %s \n", index, string(subStrBytes))
    	}
    	// find 0: 11111
    	//find 1: 22222
    	//find 2: 33333
    }

     

     

    FindAll 함수는 2개의 인자를 필요로 합니다.

    첫번째 인자는 Pattern 을 탐색할 문자열입니다.

    그리고 반드시 첫번째 인자로 사용되는 문자열은 []byte 타입으로 변경되어야 합니다.

    FindAll 함수는 반환값으로 [][]byte 를 반환하는데, 이 slice 에서 사용할 Length 값을 두번째 인자로 필요로 합니다.

     

    찾고자하는 Sub String 이 2개인 경우에 아래와 같이 FindAll 의 두번재 인자를 2로 설정하면 됩니다.

    이 경우에 총 3개의 부분 문자열이 존재하더라도 2개의 값만을 탐색하게 됩니다.

     

    output := re.FindAll(([]byte)(text), 2)
    
    for index, subStrBytes := range output {
        fmt.Printf("find %d: %s \n", index, string(subStrBytes))
    }
    // find 0: 11111
    // find 1: 22222

     

     

    반응형
Designed by Tistory.