RegExp vs String Manipulation in Go language

Published: (December 19, 2025 at 08:47 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

What is wrong?

In i, the tool I wrote this function to replace the placeholder x in a command with the package name supplied by the user.

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)
    }
}

Using regular expressions for such a simple substitution is overkill.

Getting rid of regular expressions

The task is to replace the placeholder x with the actual package name. Most commands end with that x, which makes strings.TrimSuffix() a good fit:

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

A special case is when the command ends with x as part of the package manager’s name (e.g., guix). We don’t want to replace that x. Likewise, the Nix package manager uses a dot before the package name (nix-env -iA nixpkgs.x). Therefore we need to handle both " x" and ".x" suffixes.

The revised function uses plain string manipulation:

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)
    }
}

I was curious about the performance impact.

Benchmarking RegExp vs. string replacement

I wrote a benchmark (see the source on GitHub: performance_test.go):

$ 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

Results

  • String Manipulation: ~50 ns/op
  • Regexp (pre‑compiled): ~609 ns/op (≈ 12× slower)
  • Regexp (compiled on‑the‑fly): ~2207 ns/op (≈ 44× slower)

Takeaways

  • Prefer Go’s strings functions whenever possible.
  • Avoid regular expressions for simple substitutions; they add unnecessary complexity and overhead.
  • Using strings leads to clearer, more maintainable code with better performance.

If you found this useful, feel free to share it. Follow me for more content on YouTube, Twitter (X), LinkedIn, and GitHub.

Back to Blog

Related posts

Read more »

PSX: The Project Structure Checker

PSX – Project Structure eXtractor A command‑line tool that validates your project layout and fixes it automatically. Think of it as a linter for the whole repo...