RegExp vs String Manipulation in Go 언어
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에서 팔로우하세요.