Golang中字符串命令替换方法解析(1)

Golang中字符串命令替换方法解析(1) Unix 系统中的 strings 命令用于打印文件中的可打印字符字符串。

如何用 Go 语言实现一个 strings(1) 命令的替代品?

2 回复

您可以在GNU binutils中找到strings的C语言实现

更多关于Golang中字符串命令替换方法解析(1)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现类似strings命令的功能,可以通过读取文件并提取可打印字符序列来完成。以下是一个基本实现示例:

package main

import (
	"fmt"
	"io"
	"os"
	"unicode"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: go-strings <filename>")
		os.Exit(1)
	}

	filename := os.Args[1]
	file, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error opening file: %v\n", err)
		os.Exit(1)
	}
	defer file.Close()

	printStrings(file)
}

func printStrings(r io.Reader) {
	const minLength = 4 // 最小字符串长度,与标准strings命令一致
	buf := make([]byte, 4096)
	var current []rune

	for {
		n, err := r.Read(buf)
		if err != nil && err != io.EOF {
			fmt.Fprintf(os.Stderr, "Read error: %v\n", err)
			break
		}

		if n == 0 {
			break
		}

		for i := 0; i < n; i++ {
			ch := rune(buf[i])
			
			// 检查是否为可打印ASCII字符(包括空格)
			if ch >= 32 && ch <= 126 {
				current = append(current, ch)
			} else {
				if len(current) >= minLength {
					fmt.Println(string(current))
				}
				current = nil
			}
		}

		if err == io.EOF {
			break
		}
	}

	// 处理文件末尾可能存在的字符串
	if len(current) >= minLength {
		fmt.Println(string(current))
	}
}

更完整的实现可以添加更多strings命令的选项支持:

package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"unicode"
)

type config struct {
	minLength int
	encoding  string
	radix     string
}

func main() {
	var cfg config
	flag.IntVar(&cfg.minLength, "n", 4, "minimum string length")
	flag.StringVar(&cfg.encoding, "e", "ascii", "character encoding")
	flag.StringVar(&cfg.radix, "t", "d", "radix for location (d, o, x)")
	flag.Parse()

	if flag.NArg() < 1 {
		fmt.Println("Usage: go-strings [options] <filename>")
		flag.PrintDefaults()
		os.Exit(1)
	}

	filename := flag.Arg(0)
	file, err := os.Open(filename)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
	defer file.Close()

	printStringsWithConfig(file, cfg)
}

func printStringsWithConfig(r io.Reader, cfg config) {
	buf := make([]byte, 4096)
	var current []rune
	offset := 0

	for {
		n, err := r.Read(buf)
		if err != nil && err != io.EOF {
			fmt.Fprintf(os.Stderr, "Read error: %v\n", err)
			break
		}

		if n == 0 {
			break
		}

		for i := 0; i < n; i++ {
			ch := rune(buf[i])
			
			// 根据编码类型检查字符
			var isPrintable bool
			switch cfg.encoding {
			case "ascii":
				isPrintable = ch >= 32 && ch <= 126
			case "unicode":
				isPrintable = unicode.IsPrint(ch) && ch != '\n' && ch != '\r'
			default:
				isPrintable = ch >= 32 && ch <= 126
			}

			if isPrintable {
				current = append(current, ch)
			} else {
				if len(current) >= cfg.minLength {
					printStringWithOffset(current, offset-len(current), cfg)
				}
				current = nil
			}
			offset++
		}

		if err == io.EOF {
			break
		}
	}

	if len(current) >= cfg.minLength {
		printStringWithOffset(current, offset-len(current), cfg)
	}
}

func printStringWithOffset(str []rune, offset int, cfg config) {
	var offsetStr string
	switch cfg.radix {
	case "o":
		offsetStr = fmt.Sprintf("%o", offset)
	case "x":
		offsetStr = fmt.Sprintf("%x", offset)
	default:
		offsetStr = fmt.Sprintf("%d", offset)
	}
	
	fmt.Printf("%7s: %s\n", offsetStr, string(str))
}

这个实现支持:

  • -n 选项指定最小字符串长度
  • -e 选项指定字符编码(ascii/unicode)
  • -t 选项指定偏移量显示格式

编译后使用方式:

go build -o go-strings main.go
./go-strings -n=6 -t=x sample.bin
回到顶部