golang实现Python风格文本自动换行处理的插件库textwrap的使用

Golang实现Python风格文本自动换行处理的插件库textwrap的使用

这是一个为Go语言移植的Python "textwrap"模块。虽然功能上还有些差异…

限制

目前这个模块(至少现在)不会像英语习惯那样在空白处和连字符复合词后换行。因此,break_on_hyphensbreak_long_words功能暂时还不支持。

同样,fix_sentence_endings目前也不支持,这个功能在Python中本来就不太可靠(因为它需要两个空格和其他没人关心的条件)。

连字符支持的实现已在计划中,而fix_sentence_endings则没有(但是!欢迎提交PR自由实现它)。

使用方法

使用方法与Python中非常相似:

import (
	"fmt"
	"github.com/isbm/textwrap"
)

...

text := "Your very long text here"
wrapper := textwrap.NewTextWrap() // 默认70个字符宽度
fmt.Println(wrapper.Fill(text))  // 返回字符串

// 获取每一行
for idx, line := range wrapper.Wrap(text) {
	fmt.Println(idx, line)
}

去缩进功能也已实现,工作方式与Python完全相同:

multilineText := `
    There is some multiline text
  with different identation
      everywhere. So it will be
    aligned to the minimal.
`

// 这将从每行移除两个前导空格
fmt.Println(wrapper.Dedent(multilineText))

配置

你可以通过以下方式设置包装器对象的构造函数(给出的值是默认值,你可以根据需要更改它们):

wrapper := textwrap.NewTextWrap().
	SetNewLine("\n").
	SetWidth(70),
	SetTabSpacesWidth(4).
	SetDropWhitespace(true).
	SetInitialIndent("").
	SetReplaceWhitespace(true)

额外功能

虽然可以用其他方式实现,但这个模块还提供了仅去除前导空白(TrimLeft)或仅去除尾部空白(TrimRight)的字符串空白修剪功能,与strings.TrimSpace修剪所有空白不同。

空白定义与Python的strings.whitespace相同。


更多关于golang实现Python风格文本自动换行处理的插件库textwrap的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Python风格文本自动换行处理的插件库textwrap的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 实现 Python 风格文本自动换行处理

在 Python 中,textwrap 模块提供了方便的文本自动换行功能。在 Go 中虽然没有完全相同的标准库,但我们可以通过组合标准库功能或使用第三方库来实现类似的功能。

使用标准库实现基础换行功能

Go 的 text/tabwriterstrings 包可以提供基本的换行功能:

package main

import (
	"fmt"
	"strings"
	"text/tabwriter"
	"bytes"
)

// WrapText 实现类似Python textwrap的功能
func WrapText(text string, width int) string {
	// 使用tabwriter实现简单的换行
	var buf bytes.Buffer
	w := tabwriter.NewWriter(&buf, width, 1, 1, ' ', tabwriter.DiscardEmptyColumns)
	fmt.Fprint(w, text)
	w.Flush()
	
	// 处理换行后的文本
	wrapped := buf.String()
	// 移除多余的空格
	wrapped = strings.ReplaceAll(wrapped, "\t", " ")
	wrapped = strings.ReplaceAll(wrapped, " \n", "\n")
	
	return wrapped
}

func main() {
	text := "This is a long text that needs to be wrapped to fit within a certain width. It should break at word boundaries and maintain proper spacing."
	
	wrapped := WrapText(text, 40)
	fmt.Println("Wrapped text (40 columns):")
	fmt.Println(wrapped)
	
	wrapped = WrapText(text, 60)
	fmt.Println("\nWrapped text (60 columns):")
	fmt.Println(wrapped)
}

使用第三方库实现更完整的功能

对于更完整的 Python textwrap 功能,可以使用第三方库如 github.com/mitchellh/go-wordwrap:

package main

import (
	"fmt"
	"github.com/mitchellh/go-wordwrap"
)

func main() {
	text := "This is a long text that needs to be wrapped to fit within a certain width. It should break at word boundaries and maintain proper spacing."
	
	// 基本换行
	wrapped := wordwrap.WrapString(text, 40)
	fmt.Println("Basic wrapping (40 columns):")
	fmt.Println(wrapped)
	
	// 带缩进的换行
	indented := wordwrap.WrapString(text, 36) // 40 - 4 spaces
	indented = "    " + strings.ReplaceAll(indented, "\n", "\n    ")
	fmt.Println("\nIndented wrapping (4 spaces, 40 columns total):")
	fmt.Println(indented)
}

实现更接近 Python textwrap 的完整功能

如果需要更接近 Python textwrap 的功能,可以自己实现一个更完整的版本:

package textwrap

import (
	"strings"
	"unicode"
)

// Wrap 类似于Python的textwrap.wrap
func Wrap(text string, width int, opts ...Option) []string {
	cfg := &config{width: width}
	for _, opt := range opts {
		opt(cfg)
	}

	// 处理初始缩进
	lines := strings.Split(text, "\n")
	var result []string
	
	for _, line := range lines {
		line = strings.TrimRightFunc(line, unicode.IsSpace)
		if line == "" {
			if !cfg.dropWhitespace {
				result = append(result, "")
			}
			continue
		}
		
		// 处理缩进
		indent := cfg.initialIndent
		if len(result) > 0 {
			indent = cfg.subsequentIndent
		}
		
		// 实际换行逻辑
		words := strings.Fields(line)
		var currentLine strings.Builder
		currentLine.WriteString(indent)
		currentLength := len(indent)
		
		for _, word := range words {
			if currentLength+len(word)+1 > cfg.width && currentLength > 0 {
				result = append(result, currentLine.String())
				currentLine.Reset()
				currentLine.WriteString(cfg.subsequentIndent)
				currentLength = len(cfg.subsequentIndent)
			}
			
			if currentLength > len(cfg.subsequentIndent) {
				currentLine.WriteByte(' ')
				currentLength++
			}
			
			currentLine.WriteString(word)
			currentLength += len(word)
		}
		
		if currentLine.Len() > 0 {
			result = append(result, currentLine.String())
		}
	}
	
	return result
}

type config struct {
	width            int
	initialIndent    string
	subsequentIndent string
	dropWhitespace   bool
}

type Option func(*config)

func Width(w int) Option {
	return func(c *config) {
		c.width = w
	}
}

func InitialIndent(indent string) Option {
	return func(c *config) {
		c.initialIndent = indent
	}
}

func SubsequentIndent(indent string) Option {
	return func(c *config) {
		c.subsequentIndent = indent
	}
}

func DropWhitespace(drop bool) Option {
	return func(c *config) {
		c.dropWhitespace = drop
	}
}

使用示例:

package main

import (
	"fmt"
	"./textwrap" // 假设上面的代码在textwrap包中
)

func main() {
	text := "This is a long text that needs to be wrapped to fit within a certain width. It should break at word boundaries and maintain proper spacing."
	
	// 基本换行
	wrapped := textwrap.Wrap(text, 40)
	fmt.Println("Basic wrapping (40 columns):")
	for _, line := range wrapped {
		fmt.Println(line)
	}
	
	// 带缩进的换行
	wrapped = textwrap.Wrap(text, 40, 
		textwrap.InitialIndent("    "),
		textwrap.SubsequentIndent("    "),
	)
	fmt.Println("\nIndented wrapping:")
	for _, line := range wrapped {
		fmt.Println(line)
	}
}

总结

Go 中实现 Python 风格的文本换行有几种选择:

  1. 使用标准库的简单组合实现基本功能
  2. 使用第三方库如 go-wordwrap 获得更专业的处理
  3. 自己实现完整的 textwrap 功能

根据项目需求选择最适合的方案。对于大多数简单用例,标准库组合或 go-wordwrap 就足够了。如果需要完全匹配 Python 的 textwrap 行为,可能需要自己实现更完整的版本。

回到顶部