RegExp vs String Manipulation in Go 언어

발행: (2025년 12월 19일 오후 10:47 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

위에 제공된 링크 외에 번역할 실제 텍스트가 포함되어 있지 않습니다. 번역을 원하는 본문을 알려주시면 한국어로 번역해 드리겠습니다.

무엇이 문제인가?

i에서, 사용자가 제공한 패키지 이름으로 명령어 안의 플레이스홀더 x를 교체하기 위해 이 함수를 작성했습니다.

func executeCommand(template string, pkgName string) {
    if template == "" {
        fmt.Println("Command not defined for this package manager.")
        return
    }

    re := regexp.MustCompile(`\bx\b`)
    cmdStr := re.ReplaceAllStringFunc(template, func(s string) string {
        return pkgName
    })

    if verbose {
        fmt.Printf("Executing: %s\n", cmdStr)
    }

    parts := strings.Fields(cmdStr)
    if len(parts) == 0 {
        return
    }

    head := parts[0]
    args := parts[1:]

    cmd := exec.Command(head, args...)
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    err := cmd.Run()
    if err != nil {
        if verbose {
            fmt.Printf("Error executing command: %v\n", err)
        }
        os.Exit(1)
    }
}

이처럼 간단한 치환에 정규 표현식을 사용하는 것은 과도합니다.

Source:

정규 표현식 없애기

작업은 자리 표시자 x를 실제 패키지 이름으로 교체하는 것입니다. 대부분의 명령은 x로 끝나므로 strings.TrimSuffix()가 적합합니다:

sudo apt install x
sudo apt remove x
sudo apt install --only-upgrade x
apt search x
apt show x
brew install x
brew uninstall x
brew upgrade x
brew search x
brew info x
sudo port install x
sudo port uninstall x
sudo port upgrade x
port search x
port info x
sudo flatpak install x
sudo flatpak uninstall x
sudo flatpak update x
flatpak search x
flatpak info x
sudo snap install --classic x
sudo snap remove x
sudo snap refresh x
snap find x
snap info x
sudo dnf install -y x
sudo dnf remove -y x
sudo dnf upgrade -y x
dnf search x
dnf info x
sudo pacman -S --noconfirm x
sudo pacman -Rs --noconfirm x
sudo pacman -Syu --noconfirm x
pacman -Ss x
pacman -Qi x

특수한 경우는 명령이 패키지 관리자의 이름에 x가 포함된 경우(예: guix)입니다. 이 경우 그 x는 교체하지 않아야 합니다. 마찬가지로 Nix 패키지 관리자는 패키지 이름 앞에 점(.)을 사용합니다(nix-env -iA nixpkgs.x). 따라서 " x"".x" 두 가지 접미사를 모두 처리해야 합니다.

수정된 함수는 순수 문자열 조작을 사용합니다:

func executeCommand(template string, pkgName string) {
    if template == "" {
        fmt.Println("Command not defined for this package manager.")
        return
    }

    cmdStr := template
    // If the template ends with ".x" or " x", replace the trailing "x" with pkgName
    if strings.HasSuffix(template, ".x") || strings.HasSuffix(template, " x") {
        cmdStr = strings.TrimSuffix(template, "x") + pkgName
    }

    if verbose {
        fmt.Printf("Executing: %s\n", cmdStr)
    }

    parts := strings.Fields(cmdStr)
    if len(parts) == 0 {
        return
    }

    head := parts[0]
    args := parts[1:]

    cmd := exec.Command(head, args...)
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    err := cmd.Run()
    if err != nil {
        if verbose {
            fmt.Printf("Error executing command: %v\n", err)
        }
        os.Exit(1)
    }
}

성능에 미치는 영향을 궁금해했습니다.

RegExp와 문자열 교체 벤치마크

$ go test -bench=. -run=NONE -benchmem
goos: linux
goarch: amd64
pkg: github.com/abanoubha/i
cpu: Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
BenchmarkRegexpReplacement-8             541910    2207 ns/op    1609 B/op  21 allocs/op
BenchmarkRegexpPrecompiledReplacement-8  1986163   609.2 ns/op   88 B/op    4 allocs/op
BenchmarkStringReplacement-8             23621672  50.48 ns/op   24 B/op    1 allocs/op
PASS
ok      github.com/abanoubha/i  3.608s

결과

  • 문자열 조작: ~50 ns/op
  • Regexp (미리 컴파일): ~609 ns/op (≈ 12배 느림)
  • Regexp (즉석 컴파일): ~2207 ns/op (≈ 44배 느림)

요점

  • 가능한 경우 Go의 strings 함수를 우선 사용하세요.
  • 간단한 치환에는 정규 표현식을 피하세요; 불필요한 복잡성과 오버헤드를 추가합니다.
  • strings를 사용하면 더 명확하고 유지보수가 쉬운 코드와 향상된 성능을 얻을 수 있습니다.

유용하셨다면 자유롭게 공유해 주세요. 더 많은 콘텐츠는 YouTube, Twitter (X), LinkedIn, 그리고 GitHub에서 팔로우하세요.

Back to Blog

관련 글

더 보기 »

PSX: 프로젝트 구조 검사기

PSX – Project Structure eXtractor는 프로젝트 레이아웃을 검증하고 자동으로 수정해 주는 command‑line 도구입니다. 전체 repo에 대한 linter라고 생각하면 됩니다.